Introduction

Multi-tenant SMS & Email platform providing reliable message delivery through provider integrations.

Welcome to the ExoSend API documentation. This API allows you to send SMS messages, send emails, manage sender IDs and domains, run campaigns, and monitor delivery status.

Getting Started

  1. Obtain API Token: Login to your ExoSend admin panel and navigate to your profile to generate an API token.
  2. Authentication: Include your token in the Authorization: Bearer {token} header for all requests.
  3. Base URL: All API requests should be made to the base URL shown above

Rate Limiting

API requests are rate-limited per organization. The default limit is 60 requests per minute. Contact support if you need higher limits.

Credits System

ExoSend uses a prepaid credits system. SMS messages deduct credits based on the destination country and message length. Email messages deduct credits based on the provider cost per email. Check your balance via the /balance endpoint.

As you scroll, you'll see code examples for working with the API in different programming languages in the dark area to the right (or as part of the content on mobile).


Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_API_TOKEN}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

You can retrieve your API token by logging into the ExoSend admin panel at /admin and navigating to your profile settings. Click Create New Token to generate an API token.

SMS Operations

APIs for sending SMS messages and checking delivery status.

Send Single SMS

POST
https://send.exoclass.com
/api/v1/sms/send
requires authentication

Queue a single SMS message for delivery. The message will be sent asynchronously and credits will be deducted immediately.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/sms/send" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"recipient\": \"+37061234567\",
    \"message\": \"Hello from ExoSend! Your verification code is 123456.\",
    \"sender_id\": \"EXOCLASS\"
}"
Example response:
{
    "success": true,
    "data": {
        "message_id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "status": "pending",
        "cost": 0.035,
        "segments": 1,
        "balance_remaining": 99.965
    },
    "message": "SMS queued for sending"
}
{
    "success": false,
    "error": {
        "code": "SENDER_NOT_FOUND",
        "message": "The specified sender ID was not found in your organization",
        "details": {
            "sender_id": "NONEXISTENT"
        }
    }
}
{
    "success": false,
    "error": {
        "code": "INSUFFICIENT_CREDITS",
        "message": "Your account does not have enough credits",
        "details": {
            "required": 0.035,
            "available": 0
        }
    }
}
{
    "success": false,
    "error": {
        "code": "INVALID_PHONE_NUMBER",
        "message": "The recipient phone number is invalid",
        "details": {
            "recipient": "1234567890"
        }
    }
}
{
    "success": false,
    "error": {
        "code": "SENDER_NOT_VERIFIED",
        "message": "The sender ID must be verified before sending messages",
        "details": {
            "sender_id": "EXOCLASS",
            "status": "pending",
            "status_label": "Pending Review"
        }
    }
}

Send Bulk SMS

POST
https://send.exoclass.com
/api/v1/sms/send-bulk
requires authentication

Queue multiple SMS messages to different recipients with the same content. Invalid phone numbers will be filtered out, and only valid recipients will receive messages. Credits are deducted for all valid recipients before sending.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/sms/send-bulk" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"recipients\": [
        \"+37061234567\",
        \"+37061234568\",
        \"+37061234569\"
    ],
    \"message\": \"Bulk notification: System maintenance scheduled for tonight.\",
    \"sender_id\": \"EXOCLASS\"
}"
Example response:
{
    "success": true,
    "data": {
        "total_messages": 3,
        "total_cost": 0.105,
        "balance_remaining": 99.895,
        "message_ids": [
            "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "9a7f2e5c-1234-5678-90ab-cdef12345679",
            "9a7f2e5c-1234-5678-90ab-cdef12345680"
        ],
        "invalid_recipients": []
    },
    "message": "Bulk SMS queued for sending"
}
{
    "success": true,
    "data": {
        "total_messages": 2,
        "total_cost": 0.07,
        "balance_remaining": 99.93,
        "message_ids": [
            "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "9a7f2e5c-1234-5678-90ab-cdef12345679"
        ],
        "invalid_recipients": [
            "invalid-number"
        ]
    },
    "message": "Bulk SMS queued for sending"
}
{
    "success": false,
    "error": {
        "code": "NO_VALID_RECIPIENTS",
        "message": "No valid recipients found",
        "details": {
            "invalid_recipients": [
                "invalid1",
                "invalid2"
            ]
        }
    }
}
{
    "success": false,
    "error": {
        "code": "INSUFFICIENT_CREDITS",
        "message": "Your account does not have enough credits",
        "details": {
            "required": 0.105,
            "available": 0.05,
            "valid_recipients_count": 3
        }
    }
}

Get Message Status

GET
https://send.exoclass.com
/api/v1/sms/{id}/status
requires authentication

Retrieve the current delivery status of a previously sent SMS message. Only messages belonging to your organization can be accessed.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the message.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/sms/9a7f2e5c-1234-5678-90ab-cdef12345678/status" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "status": "delivered",
        "recipient": "+37061234567",
        "cost": 0.035,
        "segments": 1,
        "sent_at": "2026-01-03T14:30:00+00:00",
        "delivered_at": "2026-01-03T14:30:15+00:00",
        "error_message": null,
        "error_code": null
    }
}
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "status": "failed",
        "recipient": "+37061234567",
        "cost": 0.035,
        "segments": 1,
        "sent_at": null,
        "delivered_at": null,
        "error_message": "Invalid recipient",
        "error_code": "INVALID_RECIPIENT"
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Message not found"
    }
}

Email Sending

APIs for sending transactional and marketing emails, checking delivery status, and listing sent emails. Credits are deducted per email sent.

Send Single Email

POST
https://send.exoclass.com
/api/v1/emails/send
requires authentication

Queue a single email for delivery. The email will be sent asynchronously via the configured email provider. Credits are deducted immediately. If html_content is provided without text_content, a plain-text version is auto-generated.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
multipart/form-data
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/emails/send" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: multipart/form-data" \
    --header "Accept: application/json" \
    --form "[email protected]"\
    --form "from_name=ExoSend Team"\
    --form "[email protected]"\
    --form "to_name=John Doe"\
    --form "subject=Welcome to ExoSend!"\
    --form "html_content=<h1>Welcome!</h1><p>Thanks for signing up.</p>"\
    --form "text_content=Welcome! Thanks for signing up."\
    --form "[email protected]"\
    --form "template_id=9a7f2e5c-1234-5678-90ab-cdef12345678"\
    --form "variables[first_name]=John"\
    --form "variables[company]=Acme"\
    --form "metadata[order_id]=12345"\
    --form "metadata[campaign]=onboarding"\
    --form "email_domain_id=9a7f2e5c-1234-5678-90ab-cdef12345678"\
    --form "attachments[]=@/tmp/php7k9snt3t716icfYDXkC" 
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "status": "pending",
        "to_email": "[email protected]",
        "subject": "Welcome to ExoSend!",
        "cost": 0.01,
        "created_at": "2026-01-15T10:30:00+00:00"
    },
    "message": "Email queued for sending."
}
{
    "success": false,
    "error": {
        "code": "INSUFFICIENT_CREDITS",
        "message": "Your account does not have enough credits",
        "details": {
            "required": 0.01,
            "available": 0
        }
    }
}
{
    "success": false,
    "error": {
        "code": "DOMAIN_NOT_VERIFIED",
        "message": "The sending domain is registered but not yet verified",
        "details": {
            "domain": "exosend.com",
            "status": "pending"
        }
    }
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "to_email": [
                "Recipient email must be a valid email address"
            ],
            "subject": [
                "Email subject is required"
            ]
        }
    }
}

Send Batch Emails

POST
https://send.exoclass.com
/api/v1/emails/send-batch
requires authentication

Queue multiple emails for delivery in a single request. Each email can have different recipients, subjects, and content. All emails are validated and credits are deducted for the entire batch before sending begins. Maximum 1000 emails per batch.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
multipart/form-data
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/emails/send-batch" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: multipart/form-data" \
    --header "Accept: application/json" \
    --form "emails[]=architecto"\
    --form "attachments[]=@/tmp/phpq5hk39o3a8is8t5oB9s" 
Example response:
{
    "success": true,
    "data": {
        "total_emails": 3,
        "total_cost": 0.03,
        "balance_remaining": 99.97,
        "email_ids": [
            "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "9a7f2e5c-1234-5678-90ab-cdef12345679",
            "9a7f2e5c-1234-5678-90ab-cdef12345680"
        ]
    },
    "message": "Batch emails queued for sending."
}
{
    "success": false,
    "error": {
        "code": "INSUFFICIENT_CREDITS",
        "message": "Your account does not have enough credits",
        "details": {
            "required": 0.03,
            "available": 0.01,
            "email_count": 3
        }
    }
}
{
    "success": false,
    "error": {
        "code": "DOMAIN_NOT_VERIFIED",
        "message": "The sending domain 'exosend.com' is registered but not yet verified",
        "details": {
            "domain": "exosend.com",
            "status": "pending"
        }
    }
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "emails": [
                "At least one email is required"
            ]
        }
    }
}

Get Batch Details

GET
https://send.exoclass.com
/api/v1/emails/batch/{batchId}
requires authentication

Retrieve the summary and paginated email list for a previously created batch. Only batches belonging to your organization can be accessed.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

batchId
string
required

The UUID of the email batch.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/emails/batch/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "batch": {
            "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "subject": "Welcome to ExoSend!",
            "from_email": "[email protected]",
            "from_name": "ExoSend Team",
            "source": "api",
            "status": "pending",
            "total_recipients": 3,
            "total_cost": 0.03,
            "total_sent": 0,
            "total_delivered": 0,
            "total_opened": 0,
            "total_bounced": 0,
            "total_failed": 0,
            "delivery_rate": 0,
            "open_rate": 0,
            "scheduled_at": null,
            "created_at": "2026-01-15T10:30:00+00:00"
        },
        "emails": {}
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Batch not found"
    }
}

Get Email Status

GET
https://send.exoclass.com
/api/v1/emails/{id}/status
requires authentication

Retrieve the current delivery status and tracking events for a previously sent email. Only emails belonging to your organization can be accessed.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the email.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/emails/9a7f2e5c-1234-5678-90ab-cdef12345678/status" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "status": "delivered",
        "to_email": "[email protected]",
        "subject": "Welcome to ExoSend!",
        "cost": 0.01,
        "sent_at": "2026-01-15T10:30:00+00:00",
        "delivered_at": "2026-01-15T10:30:05+00:00",
        "opened_at": "2026-01-15T11:00:00+00:00",
        "clicked_at": "2026-01-15T11:05:30+00:00",
        "bounced_at": null,
        "error_message": null,
        "error_code": null
    }
}
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "status": "bounced",
        "to_email": "[email protected]",
        "subject": "Welcome to ExoSend!",
        "cost": 0.01,
        "sent_at": "2026-01-15T10:30:00+00:00",
        "delivered_at": null,
        "opened_at": null,
        "clicked_at": null,
        "bounced_at": "2026-01-15T10:30:10+00:00",
        "error_message": "Mailbox not found",
        "error_code": "550"
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Email not found"
    }
}

List Sent Emails

GET
https://send.exoclass.com
/api/v1/emails
requires authentication

Retrieve a paginated list of all sent emails for your organization, sorted by newest first. Optionally filter by delivery status.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

status
string

Filter by email status. Options: pending, sent, delivered, opened, clicked, bounced, failed, complained.

Example:
delivered
per_page
integer

Number of results per page (default 25).

Example:
10
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/emails?status=delivered&per_page=10" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "emails": [
            {
                "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
                "from_email": "[email protected]",
                "to_email": "[email protected]",
                "subject": "Welcome to ExoSend!",
                "status": "delivered",
                "cost": 0.01,
                "created_at": "2026-01-15T10:30:00+00:00"
            }
        ],
        "pagination": {
            "total": 42,
            "per_page": 25,
            "current_page": 1,
            "last_page": 2
        }
    }
}

Email Domains

APIs for managing email sending domains. Domains must have proper DNS records (SPF, DKIM, DMARC) configured and verified before they can be used for sending emails.

List Domains

GET
https://send.exoclass.com
/api/v1/email-domains
requires authentication

Retrieve all email domains registered for your organization, including their verification status and DNS records.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/email-domains" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": [
        {
            "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "domain": "exosend.com",
            "from_email_default": "[email protected]",
            "from_name_default": "ExoSend",
            "status": "verified",
            "spf_verified": true,
            "dkim_verified": true,
            "dmarc_verified": true,
            "is_default": true,
            "dns_records": [
                {
                    "type": "TXT",
                    "name": "exosend.com",
                    "value": "v=spf1 include:mailgun.org ~all"
                }
            ],
            "verified_at": "2026-01-10T12:00:00+00:00",
            "created_at": "2026-01-10T10:00:00+00:00"
        }
    ]
}

Add Domain

POST
https://send.exoclass.com
/api/v1/email-domains
requires authentication

Register a new email sending domain for your organization. After adding, you must configure the returned DNS records with your domain registrar, then trigger verification. Domain registration with the email provider is done asynchronously.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/email-domains" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"domain\": \"exosend.com\",
    \"from_email_default\": \"[email protected]\",
    \"from_name_default\": \"ExoSend Team\",
    \"region\": \"eu\"
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "domain": "exosend.com",
        "from_email_default": "[email protected]",
        "from_name_default": "ExoSend Team",
        "status": "pending",
        "spf_verified": false,
        "dkim_verified": false,
        "dmarc_verified": false,
        "is_default": false,
        "dns_records": [
            {
                "type": "TXT",
                "name": "exosend.com",
                "value": "v=spf1 include:mailgun.org ~all"
            },
            {
                "type": "TXT",
                "name": "k1._domainkey.exosend.com",
                "value": "k=rsa; p=MIGf..."
            },
            {
                "type": "TXT",
                "name": "_dmarc.exosend.com",
                "value": "v=DMARC1; p=none;"
            }
        ],
        "verified_at": null,
        "created_at": "2026-01-15T10:00:00+00:00"
    },
    "message": "Domain added. Please add the DNS records shown below, then verify."
}
{
    "success": false,
    "error": {
        "code": "DOMAIN_EXISTS",
        "message": "This domain is already registered for your organization",
        "details": {
            "domain": "exosend.com"
        }
    }
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "domain": [
                "The domain field is required."
            ]
        }
    }
}

Get Domain Details

GET
https://send.exoclass.com
/api/v1/email-domains/{id}
requires authentication

Retrieve full details of a specific email domain, including DNS records and verification status for SPF, DKIM, and DMARC.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the domain.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/email-domains/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "domain": "exosend.com",
        "from_email_default": "[email protected]",
        "from_name_default": "ExoSend Team",
        "status": "verified",
        "spf_verified": true,
        "dkim_verified": true,
        "dmarc_verified": true,
        "is_default": true,
        "dns_records": [
            {
                "type": "TXT",
                "name": "exosend.com",
                "value": "v=spf1 include:mailgun.org ~all"
            }
        ],
        "verified_at": "2026-01-10T12:00:00+00:00",
        "created_at": "2026-01-10T10:00:00+00:00"
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Domain not found"
    }
}

Verify Domain DNS

POST
https://send.exoclass.com
/api/v1/email-domains/{id}/verify
requires authentication

Trigger DNS verification for a domain. This queues a background job that checks whether the required SPF, DKIM, and DMARC records are properly configured. The domain status will be updated asynchronously after verification completes.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the domain.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/email-domains/9a7f2e5c-1234-5678-90ab-cdef12345678/verify" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "domain": "exosend.com",
        "from_email_default": "[email protected]",
        "from_name_default": "ExoSend Team",
        "status": "pending",
        "spf_verified": false,
        "dkim_verified": false,
        "dmarc_verified": false,
        "is_default": false,
        "dns_records": [],
        "verified_at": null,
        "created_at": "2026-01-15T10:00:00+00:00"
    },
    "message": "DNS verification has been queued."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Domain not found"
    }
}

Set Default Domain

PATCH
https://send.exoclass.com
/api/v1/email-domains/{id}/default
requires authentication

Set a verified domain as the default sending domain for your organization. Only verified domains can be set as default. The previous default domain will be automatically unset.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the domain.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request PATCH \
    "https://send.exoclass.com/api/v1/email-domains/9a7f2e5c-1234-5678-90ab-cdef12345678/default" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "domain": "exosend.com",
        "from_email_default": "[email protected]",
        "from_name_default": "ExoSend Team",
        "status": "verified",
        "spf_verified": true,
        "dkim_verified": true,
        "dmarc_verified": true,
        "is_default": true,
        "dns_records": [],
        "verified_at": "2026-01-10T12:00:00+00:00",
        "created_at": "2026-01-10T10:00:00+00:00"
    },
    "message": "Domain set as default."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Domain not found"
    }
}
{
    "success": false,
    "error": {
        "code": "DOMAIN_NOT_VERIFIED",
        "message": "Only verified domains can be set as default"
    }
}

Delete Domain

DELETE
https://send.exoclass.com
/api/v1/email-domains/{id}
requires authentication

Remove an email domain from your organization. This does not affect emails that have already been sent through this domain.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the domain.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request DELETE \
    "https://send.exoclass.com/api/v1/email-domains/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": null,
    "message": "Domain removed."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Domain not found"
    }
}

Email Templates

APIs for managing reusable email templates with variable substitution. Templates support MJML, HTML, and plain-text content with merge tags for personalization. System templates are shared across all organizations and cannot be edited by non-admins.

List Templates

GET
https://send.exoclass.com
/api/v1/email-templates
requires authentication

Retrieve all active email templates for your organization, including system templates. Optionally filter by category. Returns summary data; use the show endpoint for full content.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

category
string

Filter by template category. Options: transactional, marketing, notification, onboarding, custom.

Example:
marketing
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/email-templates?category=marketing" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": [
        {
            "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "name": "Welcome Email",
            "slug": "welcome-email",
            "category": "onboarding",
            "subject_template": "Welcome, {{first_name}}!",
            "is_system": false,
            "is_active": true,
            "version": 1,
            "times_used": 150,
            "created_at": "2026-01-10T10:00:00+00:00",
            "updated_at": "2026-01-12T14:30:00+00:00"
        }
    ]
}

Create Template

POST
https://send.exoclass.com
/api/v1/email-templates
requires authentication

Create a new email template for your organization. Templates can include merge tag variables (e.g., {{first_name}}) that are replaced at send time. If only html_content is provided, a plain-text version is auto-generated.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/email-templates" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Monthly Newsletter\",
    \"slug\": \"monthly-newsletter\",
    \"category\": \"marketing\",
    \"subject_template\": \"Your {{month}} Newsletter\",
    \"html_content\": \"<h1>Hello {{first_name}}<\\/h1><p>Here is your newsletter.<\\/p>\",
    \"text_content\": \"Hello {{first_name}}, here is your newsletter.\",
    \"mjml_content\": \"<mjml><mj-body><mj-section><mj-column><mj-text>Hello<\\/mj-text><\\/mj-column><\\/mj-section><\\/mj-body><\\/mjml>\",
    \"description\": \"Sent monthly with latest updates\",
    \"variables\": [
        \"architecto\"
    ]
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "Monthly Newsletter",
        "slug": "monthly-newsletter",
        "category": "marketing",
        "subject_template": "Your {{month}} Newsletter",
        "is_system": false,
        "is_active": true,
        "version": 1,
        "times_used": 0,
        "created_at": "2026-01-15T10:00:00+00:00",
        "updated_at": "2026-01-15T10:00:00+00:00",
        "description": "Sent monthly with latest updates",
        "html_content": "<h1>Hello {{first_name}}</h1><p>Here is your newsletter.</p>",
        "text_content": "Hello {{first_name}}, here is your newsletter.",
        "mjml_content": null,
        "variables": [
            {
                "key": "first_name",
                "label": "First Name",
                "default": "there",
                "required": true
            }
        ]
    },
    "message": "Template created."
}
{
    "success": false,
    "error": {
        "code": "SLUG_EXISTS",
        "message": "A template with this slug already exists"
    }
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "name": [
                "The name field is required."
            ],
            "category": [
                "The selected category is invalid."
            ]
        }
    }
}

Get Template Details

GET
https://send.exoclass.com
/api/v1/email-templates/{id}
requires authentication

Retrieve full details of a specific email template, including HTML content, text content, MJML source, and variable definitions.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the template.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/email-templates/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "Welcome Email",
        "slug": "welcome-email",
        "category": "onboarding",
        "subject_template": "Welcome, {{first_name}}!",
        "is_system": false,
        "is_active": true,
        "version": 1,
        "times_used": 150,
        "created_at": "2026-01-10T10:00:00+00:00",
        "updated_at": "2026-01-12T14:30:00+00:00",
        "description": "Sent to new users after registration",
        "html_content": "<h1>Welcome, {{first_name}}!</h1><p>Thanks for joining.</p>",
        "text_content": "Welcome, {{first_name}}! Thanks for joining.",
        "mjml_content": null,
        "variables": [
            {
                "key": "first_name",
                "label": "First Name",
                "default": "there",
                "required": true
            }
        ]
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Template not found"
    }
}

Update Template

PUT
https://send.exoclass.com
/api/v1/email-templates/{id}
requires authentication

Update an existing email template. Only organization-owned templates can be edited; system templates require super admin privileges. All fields are optional; only provided fields will be updated.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the template.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678

Body Parameters

Example request:
curl --request PUT \
    "https://send.exoclass.com/api/v1/email-templates/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Monthly Newsletter v2\",
    \"category\": \"marketing\",
    \"subject_template\": \"Your {{month}} Newsletter - Updated\",
    \"html_content\": \"<h1>Hello {{first_name}}<\\/h1><p>New content.<\\/p>\",
    \"text_content\": \"Hello {{first_name}}, new content.\",
    \"description\": \"Updated monthly newsletter\",
    \"variables\": [
        \"architecto\"
    ],
    \"is_active\": true
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "Monthly Newsletter v2",
        "slug": "monthly-newsletter",
        "category": "marketing",
        "subject_template": "Your {{month}} Newsletter - Updated",
        "is_system": false,
        "is_active": true,
        "version": 1,
        "times_used": 150,
        "created_at": "2026-01-10T10:00:00+00:00",
        "updated_at": "2026-01-15T14:30:00+00:00",
        "description": "Updated monthly newsletter",
        "html_content": "<h1>Hello {{first_name}}</h1><p>New content.</p>",
        "text_content": "Hello {{first_name}}, new content.",
        "mjml_content": null,
        "variables": []
    },
    "message": "Template updated."
}
{
    "success": false,
    "error": {
        "code": "FORBIDDEN",
        "message": "System templates cannot be edited"
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Template not found"
    }
}

Delete Template

DELETE
https://send.exoclass.com
/api/v1/email-templates/{id}
requires authentication

Soft-delete an email template. System templates require super admin privileges to delete. Deleted templates are no longer available for sending but their data is preserved for historical reference.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the template.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request DELETE \
    "https://send.exoclass.com/api/v1/email-templates/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": null,
    "message": "Template deleted."
}
{
    "success": false,
    "error": {
        "code": "FORBIDDEN",
        "message": "System templates cannot be deleted"
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Template not found"
    }
}

Preview Template

POST
https://send.exoclass.com
/api/v1/email-templates/{id}/preview
requires authentication

Render a template with sample data and return the resulting subject, HTML, and plain-text content. Useful for previewing how merge tags will be replaced before sending. Pass variable values in the data object.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the template.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/email-templates/9a7f2e5c-1234-5678-90ab-cdef12345678/preview" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"data\": {
        \"first_name\": \"John\",
        \"month\": \"January\"
    }
}"
Example response:
{
    "success": true,
    "data": {
        "subject": "Welcome, John!",
        "html_content": "<h1>Welcome, John!</h1><p>Thanks for joining.</p>",
        "text_content": "Welcome, John! Thanks for joining."
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Template not found"
    }
}

Duplicate Template

POST
https://send.exoclass.com
/api/v1/email-templates/{id}/duplicate
requires authentication

Create a copy of an existing template in your organization. The copy will have " (Copy)" appended to its name and a unique slug with a timestamp suffix. Useful for customizing system templates or creating variations of existing ones.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the template to duplicate.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/email-templates/9a7f2e5c-1234-5678-90ab-cdef12345678/duplicate" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9b8f3e6d-2345-6789-01bc-def123456789",
        "name": "Welcome Email (Copy)",
        "slug": "welcome-email-copy-1705312200",
        "category": "onboarding",
        "subject_template": "Welcome, {{first_name}}!",
        "is_system": false,
        "is_active": true,
        "version": 1,
        "times_used": 0,
        "created_at": "2026-01-15T10:30:00+00:00",
        "updated_at": "2026-01-15T10:30:00+00:00",
        "description": "Sent to new users after registration",
        "html_content": "<h1>Welcome, {{first_name}}!</h1><p>Thanks for joining.</p>",
        "text_content": "Welcome, {{first_name}}! Thanks for joining.",
        "mjml_content": null,
        "variables": [
            {
                "key": "first_name",
                "label": "First Name",
                "default": "there",
                "required": true
            }
        ]
    },
    "message": "Template duplicated."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Template not found"
    }
}

Email Campaigns

APIs for creating, managing, and sending email campaigns. Campaigns follow a lifecycle: draft -> sending/scheduled -> completed/cancelled. Only draft campaigns can be edited or deleted.

List Campaigns

GET
https://send.exoclass.com
/api/v1/campaigns
requires authentication

Retrieve a paginated list of all email campaigns for your organization, sorted by newest first. Optionally filter by campaign status.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

status
string

Filter by campaign status. Options: draft, scheduled, sending, paused, completed, cancelled, failed.

Example:
draft
per_page
integer

Number of results per page (default 25).

Example:
10
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/campaigns?status=draft&per_page=10" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "data": [
            {
                "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
                "name": "January Newsletter",
                "status": "completed",
                "subject": "Your January Update",
                "from_email": "[email protected]",
                "total_recipients": 5000,
                "total_sent": 4980,
                "total_opened": 2100,
                "total_clicked": 450,
                "total_bounced": 20,
                "created_at": "2026-01-10T10:00:00+00:00"
            }
        ],
        "pagination": {
            "total": 15,
            "per_page": 25,
            "current_page": 1,
            "last_page": 1
        }
    }
}

Create Campaign

POST
https://send.exoclass.com
/api/v1/campaigns
requires authentication

Create a new email campaign in draft status. The campaign can then be sent immediately or scheduled for later delivery. You can specify target contact lists and optionally use a pre-built template.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/campaigns" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"January Newsletter\",
    \"description\": \"Monthly newsletter for January 2026\",
    \"email_template_id\": \"9a7f2e5c-1234-5678-90ab-cdef12345678\",
    \"subject\": \"Your January Update\",
    \"html_content\": \"<h1>January Update<\\/h1><p>Here are our latest updates.<\\/p>\",
    \"text_content\": \"Here are our latest updates.\",
    \"template_variables\": {
        \"month\": \"January\",
        \"year\": \"2026\"
    },
    \"email_domain_id\": \"9a7f2e5c-1234-5678-90ab-cdef12345678\",
    \"from_email\": \"[email protected]\",
    \"from_name\": \"ExoSend Team\",
    \"reply_to\": \"[email protected]\",
    \"target_list_ids\": [
        \"9a7f2e5c-1234-5678-90ab-cdef12345678\"
    ],
    \"segment_filters\": {
        \"status\": \"active\"
    },
    \"send_rate_per_minute\": 500,
    \"batch_size\": 100,
    \"timezone\": \"Asia\\/Yekaterinburg\",
    \"scheduled_at\": \"2026-03-04T23:25:31\"
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "January Newsletter",
        "status": "draft",
        "subject": "Your January Update",
        "from_email": "[email protected]",
        "from_name": "ExoSend Team",
        "total_recipients": 0,
        "total_sent": 0,
        "created_at": "2026-01-15T10:00:00+00:00"
    },
    "message": "Campaign created."
}
{
    "success": false,
    "error": {
        "code": "INVALID_LIST",
        "message": "One or more target lists do not exist or do not belong to your organization"
    }
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "name": [
                "The name field is required."
            ],
            "subject": [
                "The subject field is required."
            ]
        }
    }
}

Get Campaign Details

GET
https://send.exoclass.com
/api/v1/campaigns/{id}
requires authentication

Retrieve full details of a specific campaign, including computed engagement rates (open rate, click rate, bounce rate) if the campaign has been sent.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "January Newsletter",
        "status": "completed",
        "subject": "Your January Update",
        "from_email": "[email protected]",
        "from_name": "ExoSend Team",
        "total_recipients": 5000,
        "total_sent": 4980,
        "total_opened": 2100,
        "total_clicked": 450,
        "total_bounced": 20,
        "open_rate": "42.2%",
        "click_rate": "9.0%",
        "bounce_rate": "0.4%",
        "created_at": "2026-01-10T10:00:00+00:00",
        "sent_at": "2026-01-10T12:00:00+00:00",
        "completed_at": "2026-01-10T13:30:00+00:00"
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}

Update Campaign

PUT
https://send.exoclass.com
/api/v1/campaigns/{id}
requires authentication

Update an existing campaign. Only campaigns in draft status can be updated. All fields are optional; only provided fields will be modified.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678

Body Parameters

Example request:
curl --request PUT \
    "https://send.exoclass.com/api/v1/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"January Newsletter v2\",
    \"description\": \"Revised newsletter content\",
    \"email_template_id\": \"9a7f2e5c-1234-5678-90ab-cdef12345678\",
    \"subject\": \"Your Updated January Newsletter\",
    \"html_content\": \"<h1>Updated Content<\\/h1>\",
    \"text_content\": \"Updated content.\",
    \"template_variables\": {
        \"month\": \"February\"
    },
    \"from_email\": \"[email protected]\",
    \"from_name\": \"ExoSend Newsletter\",
    \"reply_to\": \"[email protected]\",
    \"target_list_ids\": [
        \"9a7f2e5c-1234-5678-90ab-cdef12345678\"
    ],
    \"send_rate_per_minute\": 300,
    \"timezone\": \"Asia\\/Yekaterinburg\",
    \"scheduled_at\": \"2026-03-04T23:25:31\"
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "January Newsletter v2",
        "status": "draft",
        "subject": "Your Updated January Newsletter",
        "from_email": "[email protected]",
        "created_at": "2026-01-10T10:00:00+00:00",
        "updated_at": "2026-01-15T14:30:00+00:00"
    },
    "message": "Campaign updated."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}
{
    "success": false,
    "error": {
        "code": "INVALID_STATUS",
        "message": "Only draft campaigns can be updated"
    }
}
{
    "success": false,
    "error": {
        "code": "INVALID_LIST",
        "message": "One or more target lists do not exist or do not belong to your organization"
    }
}

Send Campaign

POST
https://send.exoclass.com
/api/v1/campaigns/{id}/send
requires authentication

Start sending a draft campaign immediately. The campaign status will change to "sending" and emails will be dispatched to all target recipients asynchronously.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678/send" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "January Newsletter",
        "status": "sending",
        "total_recipients": 5000,
        "sent_at": "2026-01-15T12:00:00+00:00"
    },
    "message": "Campaign sending started."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}
{
    "success": false,
    "error": {
        "code": "INVALID_STATUS",
        "message": "Only draft campaigns can be sent"
    }
}

Schedule Campaign

POST
https://send.exoclass.com
/api/v1/campaigns/{id}/schedule
requires authentication

Schedule a draft campaign for future delivery at the specified date and time. The campaign status will change to "scheduled" and sending will begin automatically at the scheduled time.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678/schedule" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"scheduled_at\": \"2026-02-01T09:00:00Z\",
    \"timezone\": \"Asia\\/Yekaterinburg\"
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "January Newsletter",
        "status": "scheduled",
        "scheduled_at": "2026-02-01T09:00:00+00:00"
    },
    "message": "Campaign scheduled."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}
{
    "success": false,
    "error": {
        "code": "INVALID_STATUS",
        "message": "Only draft campaigns can be scheduled"
    }
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "scheduled_at": [
                "The scheduled at must be a date after now."
            ]
        }
    }
}

Pause Campaign

POST
https://send.exoclass.com
/api/v1/campaigns/{id}/pause
requires authentication

Pause a campaign that is currently sending. Emails already queued will still be delivered, but no new emails will be dispatched until the campaign is resumed.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678/pause" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "January Newsletter",
        "status": "paused",
        "total_sent": 2500,
        "total_recipients": 5000
    },
    "message": "Campaign paused."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}
{
    "success": false,
    "error": {
        "code": "INVALID_STATUS",
        "message": "Only sending campaigns can be paused"
    }
}

Resume Campaign

POST
https://send.exoclass.com
/api/v1/campaigns/{id}/resume
requires authentication

Resume a previously paused campaign. Email dispatch will continue from where it left off, sending to remaining recipients.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678/resume" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "January Newsletter",
        "status": "sending",
        "total_sent": 2500,
        "total_recipients": 5000
    },
    "message": "Campaign resumed."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}
{
    "success": false,
    "error": {
        "code": "INVALID_STATUS",
        "message": "Only paused campaigns can be resumed"
    }
}

Cancel Campaign

POST
https://send.exoclass.com
/api/v1/campaigns/{id}/cancel
requires authentication

Cancel a campaign that is in draft, scheduled, sending, or paused status. Completed or already-cancelled campaigns cannot be cancelled. Emails already sent will not be affected.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678/cancel" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "January Newsletter",
        "status": "cancelled",
        "total_sent": 2500,
        "total_recipients": 5000
    },
    "message": "Campaign cancelled."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}
{
    "success": false,
    "error": {
        "code": "INVALID_STATUS",
        "message": "This campaign cannot be cancelled"
    }
}

Delete Campaign

DELETE
https://send.exoclass.com
/api/v1/campaigns/{id}
requires authentication

Permanently delete a draft campaign. Only campaigns in draft status can be deleted. Campaigns that have been sent, scheduled, or completed cannot be deleted.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request DELETE \
    "https://send.exoclass.com/api/v1/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": null,
    "message": "Campaign deleted."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}
{
    "success": false,
    "error": {
        "code": "INVALID_STATUS",
        "message": "Only draft campaigns can be deleted"
    }
}

Contacts

APIs for managing email contacts. Contacts are individual email recipients that can be organized into lists for campaign targeting. Supports CRUD operations and CSV import.

List Contacts

GET
https://send.exoclass.com
/api/v1/contacts
requires authentication

Retrieve a paginated list of all contacts for your organization. Supports filtering by status and full-text search across email, first name, and last name.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

status
string

Filter by contact status. Options: active, unsubscribed, bounced, complained.

Example:
active
search
string

Search contacts by email, first name, or last name.

Example:
john
per_page
integer

Number of results per page (default 25).

Example:
50
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/contacts?status=active&search=john&per_page=50" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "data": [
            {
                "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
                "email": "[email protected]",
                "first_name": "John",
                "last_name": "Doe",
                "status": "active",
                "custom_fields": {
                    "company": "Acme Inc"
                },
                "subscribed_at": "2026-01-10T10:00:00+00:00",
                "created_at": "2026-01-10T10:00:00+00:00"
            }
        ],
        "pagination": {
            "total": 1250,
            "per_page": 25,
            "current_page": 1,
            "last_page": 50
        }
    }
}

Create Contact

POST
https://send.exoclass.com
/api/v1/contacts
requires authentication

Add a new contact to your organization. The contact will be automatically subscribed upon creation. Each email address must be unique within the organization.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/contacts" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"[email protected]\",
    \"first_name\": \"John\",
    \"last_name\": \"Doe\",
    \"custom_fields\": {
        \"company\": \"Acme Inc\",
        \"role\": \"Developer\"
    }
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "email": "[email protected]",
        "first_name": "John",
        "last_name": "Doe",
        "status": "active",
        "custom_fields": {
            "company": "Acme Inc",
            "role": "Developer"
        },
        "subscribed_at": "2026-01-15T10:00:00+00:00",
        "created_at": "2026-01-15T10:00:00+00:00"
    },
    "message": "Contact created."
}
{
    "success": false,
    "error": {
        "code": "CONTACT_EXISTS",
        "message": "A contact with this email already exists"
    }
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "email": [
                "The email field is required."
            ]
        }
    }
}

Update Contact

PUT
https://send.exoclass.com
/api/v1/contacts/{id}
requires authentication

Update an existing contact's information. All fields are optional; only provided fields will be modified.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the contact.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678

Body Parameters

Example request:
curl --request PUT \
    "https://send.exoclass.com/api/v1/contacts/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"[email protected]\",
    \"first_name\": \"Jane\",
    \"last_name\": \"Smith\",
    \"custom_fields\": {
        \"company\": \"New Corp\"
    },
    \"status\": \"unsubscribed\"
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "email": "[email protected]",
        "first_name": "Jane",
        "last_name": "Smith",
        "status": "active",
        "custom_fields": {
            "company": "New Corp"
        },
        "subscribed_at": "2026-01-10T10:00:00+00:00",
        "created_at": "2026-01-10T10:00:00+00:00",
        "updated_at": "2026-01-15T14:30:00+00:00"
    },
    "message": "Contact updated."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Contact not found"
    }
}

Delete Contact

DELETE
https://send.exoclass.com
/api/v1/contacts/{id}
requires authentication

Permanently delete a contact from your organization. This also removes the contact from all associated contact lists.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the contact.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request DELETE \
    "https://send.exoclass.com/api/v1/contacts/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": null,
    "message": "Contact deleted."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Contact not found"
    }
}

Import Contacts from CSV

POST
https://send.exoclass.com
/api/v1/contacts/import
requires authentication

Import contacts from a CSV file. The CSV should have columns for email, first_name, and last_name (at minimum). Duplicate emails are automatically skipped. Optionally assign all imported contacts to a specific contact list. Maximum file size: 10MB.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
multipart/form-data
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/contacts/import" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: multipart/form-data" \
    --header "Accept: application/json" \
    --form "list_id=9a7f2e5c-1234-5678-90ab-cdef12345678"\
    --form "file=@/tmp/phpb1tib3c2s0gkfcKCrJW" 
Example response:
{
    "success": true,
    "data": {
        "imported": 450,
        "skipped": 12,
        "errors": [
            {
                "row": 5,
                "error": "Invalid email format"
            },
            {
                "row": 23,
                "error": "Missing required email field"
            }
        ]
    },
    "message": "Import completed."
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "file": [
                "The file field is required."
            ],
            "list_id": [
                "The list id must be a valid UUID."
            ]
        }
    }
}

Contact Lists

APIs for managing contact lists. Lists are collections of contacts used for targeting email campaigns. Contacts can belong to multiple lists simultaneously.

List Contact Lists

GET
https://send.exoclass.com
/api/v1/contact-lists
requires authentication

Retrieve a paginated list of all contact lists for your organization, including the number of contacts in each list.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

per_page
integer

Number of results per page (default 25).

Example:
10
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/contact-lists?per_page=10" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "data": [
            {
                "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
                "name": "Newsletter Subscribers",
                "description": "Users who opted in to the monthly newsletter",
                "is_default": true,
                "contacts_count": 3500,
                "created_at": "2026-01-10T10:00:00+00:00",
                "updated_at": "2026-01-15T14:30:00+00:00"
            }
        ],
        "pagination": {
            "total": 8,
            "per_page": 25,
            "current_page": 1,
            "last_page": 1
        }
    }
}

Create Contact List

POST
https://send.exoclass.com
/api/v1/contact-lists
requires authentication

Create a new contact list for your organization. List names must be unique within the organization.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/contact-lists" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Newsletter Subscribers\",
    \"description\": \"Users who opted in to the monthly newsletter\",
    \"is_default\": false
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "Newsletter Subscribers",
        "description": "Users who opted in to the monthly newsletter",
        "is_default": false,
        "created_at": "2026-01-15T10:00:00+00:00",
        "updated_at": "2026-01-15T10:00:00+00:00"
    },
    "message": "Contact list created."
}
{
    "success": false,
    "error": {
        "code": "LIST_EXISTS",
        "message": "A list with this name already exists"
    }
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "name": [
                "The name field is required."
            ]
        }
    }
}

Update Contact List

PUT
https://send.exoclass.com
/api/v1/contact-lists/{id}
requires authentication

Update an existing contact list's name, description, or default status. All fields are optional; only provided fields will be modified.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the contact list.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678

Body Parameters

Example request:
curl --request PUT \
    "https://send.exoclass.com/api/v1/contact-lists/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Premium Subscribers\",
    \"description\": \"Premium tier newsletter subscribers\",
    \"is_default\": true
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "name": "Premium Subscribers",
        "description": "Premium tier newsletter subscribers",
        "is_default": true,
        "created_at": "2026-01-10T10:00:00+00:00",
        "updated_at": "2026-01-15T14:30:00+00:00"
    },
    "message": "Contact list updated."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Contact list not found"
    }
}

Delete Contact List

DELETE
https://send.exoclass.com
/api/v1/contact-lists/{id}
requires authentication

Delete a contact list. This removes the list itself but does not delete the contacts that were in the list. Contacts will remain in the organization.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the contact list.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request DELETE \
    "https://send.exoclass.com/api/v1/contact-lists/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": null,
    "message": "Contact list deleted."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Contact list not found"
    }
}

Add Contacts to List

POST
https://send.exoclass.com
/api/v1/contact-lists/{id}/contacts
requires authentication

Add one or more existing contacts to a contact list. Contacts that are already in the list will be silently skipped (no duplicates). All contact IDs must belong to your organization.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the contact list.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/contact-lists/9a7f2e5c-1234-5678-90ab-cdef12345678/contacts" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"contact_ids\": [
        \"9a7f2e5c-1234-5678-90ab-cdef12345678\",
        \"9b8f3e6d-2345-6789-01bc-def123456789\"
    ]
}"
Example response:
{
    "success": true,
    "data": null,
    "message": "Contacts added to list."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Contact list not found"
    }
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "contact_ids": [
                "The contact ids field is required."
            ]
        }
    }
}

Remove Contact from List

DELETE
https://send.exoclass.com
/api/v1/contact-lists/{id}/contacts/{contactId}
requires authentication

Remove a single contact from a contact list. The contact itself is not deleted and remains in the organization. If the contact is not in the list, the operation completes silently.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the contact list.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
contactId
string
required

The UUID of the contact to remove.

Example:
9b8f3e6d-2345-6789-01bc-def123456789
Example request:
curl --request DELETE \
    "https://send.exoclass.com/api/v1/contact-lists/9a7f2e5c-1234-5678-90ab-cdef12345678/contacts/9b8f3e6d-2345-6789-01bc-def123456789" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": null,
    "message": "Contact removed from list."
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Contact list not found"
    }
}

Analytics

APIs for retrieving email analytics and engagement metrics. Includes organization-level overviews, per-campaign statistics, link tracking, device breakdowns, and individual email event timelines.

Organization Overview

GET
https://send.exoclass.com
/api/v1/analytics/overview
requires authentication

Retrieve aggregate email analytics for your organization over a specified date range. Includes totals for sent, delivered, opened, clicked, bounced, and complained emails.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

from
string

optional Start date for the analytics period (ISO 8601 format). Defaults to 30 days ago.

Example:
2026-01-01
to
string

optional End date for the analytics period (ISO 8601 format). Defaults to today.

Example:
2026-01-31
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/analytics/overview?from=2026-01-01&to=2026-01-31" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "total_sent": 12500,
        "total_delivered": 12300,
        "total_opened": 5200,
        "total_clicked": 1100,
        "total_bounced": 150,
        "total_complained": 5,
        "delivery_rate": 98.4,
        "open_rate": 42.3,
        "click_rate": 8.9,
        "bounce_rate": 1.2
    }
}

Campaign Analytics

GET
https://send.exoclass.com
/api/v1/analytics/campaigns/{id}
requires authentication

Retrieve detailed analytics for a specific email campaign, including delivery, engagement, and bounce statistics.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/analytics/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "campaign_id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "campaign_name": "January Newsletter",
        "total_sent": 5000,
        "total_delivered": 4950,
        "total_opened": 2100,
        "total_clicked": 450,
        "total_bounced": 50,
        "total_complained": 2,
        "open_rate": 42.4,
        "click_rate": 9.1,
        "bounce_rate": 1,
        "unsubscribe_rate": 0.3
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}
GET
https://send.exoclass.com
/api/v1/analytics/campaigns/{id}/links
requires authentication

Retrieve click-tracking data for all links in a campaign, sorted by total clicks. Shows which URLs were clicked and how many times.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/analytics/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678/links" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:

Campaign Device Breakdown

GET
https://send.exoclass.com
/api/v1/analytics/campaigns/{id}/devices
requires authentication

Retrieve device and email client breakdown for a campaign. Shows which devices, operating systems, and email clients recipients used to open the campaign emails.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the campaign.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/analytics/campaigns/9a7f2e5c-1234-5678-90ab-cdef12345678/devices" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "devices": [
            {
                "device": "Desktop",
                "count": 1200,
                "percentage": 57.1
            },
            {
                "device": "Mobile",
                "count": 750,
                "percentage": 35.7
            },
            {
                "device": "Tablet",
                "count": 150,
                "percentage": 7.1
            }
        ],
        "clients": [
            {
                "client": "Gmail",
                "count": 900,
                "percentage": 42.9
            },
            {
                "client": "Apple Mail",
                "count": 600,
                "percentage": 28.6
            },
            {
                "client": "Outlook",
                "count": 350,
                "percentage": 16.7
            }
        ]
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Campaign not found"
    }
}

Email Event Timeline

GET
https://send.exoclass.com
/api/v1/analytics/emails/{id}/events
requires authentication

Retrieve the full event timeline for a specific email, including delivery, open, click, bounce, and complaint events in chronological order.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the email.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/analytics/emails/9a7f2e5c-1234-5678-90ab-cdef12345678/events" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": [
        {
            "id": "9b8f3e6d-2345-6789-01bc-def123456789",
            "email_id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "event_type": "delivered",
            "occurred_at": "2026-01-15T10:30:05+00:00",
            "metadata": {
                "smtp_code": 250
            }
        },
        {
            "id": "9c9f4f7e-3456-7890-12cd-ef1234567890",
            "email_id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "event_type": "opened",
            "occurred_at": "2026-01-15T11:00:00+00:00",
            "metadata": {
                "user_agent": "Mozilla/5.0",
                "ip": "192.168.1.1"
            }
        },
        {
            "id": "9d0f5g8f-4567-8901-23de-f12345678901",
            "email_id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "event_type": "clicked",
            "occurred_at": "2026-01-15T11:05:30+00:00",
            "metadata": {
                "url": "https://exosend.com/pricing",
                "user_agent": "Mozilla/5.0"
            }
        }
    ]
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Email not found"
    }
}

Suppression List

APIs for managing your email suppression list. Suppressed email addresses will not receive any emails from your organization. Addresses can be suppressed manually, or automatically via bounces, complaints, and unsubscribes.

List Suppressions

GET
https://send.exoclass.com
/api/v1/suppressions
requires authentication

Retrieve a paginated list of all suppressed email addresses for your organization. Optionally filter by suppression reason.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

reason
string

Filter by suppression reason. Options: hard_bounce, soft_bounce, complaint, unsubscribed, manual, list_import.

Example:
hard_bounce
per_page
integer

Number of results per page (default 25).

Example:
50
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/suppressions?reason=hard_bounce&per_page=50" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "data": [
            {
                "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
                "email": "[email protected]",
                "reason": "hard_bounce",
                "details": "550 Mailbox not found",
                "created_at": "2026-01-10T10:00:00+00:00"
            },
            {
                "id": "9b8f3e6d-2345-6789-01bc-def123456789",
                "email": "[email protected]",
                "reason": "unsubscribed",
                "details": null,
                "created_at": "2026-01-12T15:30:00+00:00"
            }
        ],
        "pagination": {
            "total": 25,
            "per_page": 25,
            "current_page": 1,
            "last_page": 1
        }
    }
}

Suppress Email Address

POST
https://send.exoclass.com
/api/v1/suppressions
requires authentication

Add an email address to your organization's suppression list. Suppressed addresses will not receive any future emails. If the address is already suppressed, the existing suppression record is returned.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/suppressions" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"[email protected]\",
    \"reason\": \"manual\",
    \"details\": \"Requested removal via support ticket #1234\"
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "email": "[email protected]",
        "reason": "manual",
        "details": "Requested removal via support ticket #1234",
        "created_at": "2026-01-15T10:00:00+00:00"
    },
    "message": "Email suppressed."
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "email": [
                "The email field is required."
            ],
            "reason": [
                "The selected reason is invalid."
            ]
        }
    }
}

Unsuppress Email Address

DELETE
https://send.exoclass.com
/api/v1/suppressions/{email}
requires authentication

Remove an email address from your organization's suppression list, allowing future emails to be delivered to this address again.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

email
string
required

The email address to unsuppress.

Example request:
curl --request DELETE \
    "https://send.exoclass.com/api/v1/suppressions/[email protected]" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:

Check Suppression Status

GET
https://send.exoclass.com
/api/v1/suppressions/check/{email}
requires authentication

Check whether a specific email address is on your organization's suppression list. Returns a boolean indicating the suppression status.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

email
string
required

The email address to check.

Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/suppressions/check/[email protected]" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:

Account Management

APIs for managing your ExoSend account balance and credits.

Get Credit Balance

GET
https://send.exoclass.com
/api/v1/balance
requires authentication

Retrieve your organization's current credit balance. Credits are used to send SMS messages, with costs varying by destination country and message length.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/balance" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "balance": 99.965,
        "currency": "EUR",
        "organization": "ExoClass"
    }
}

Sender ID Management

APIs for managing sender IDs (sender names that appear on SMS messages). Sender IDs must be approved by administrators and verified by providers before use.

List Sender IDs

GET
https://send.exoclass.com
/api/v1/sender-ids
requires authentication

Retrieve all sender IDs for your organization with optional status filtering. By default, only verified sender IDs are returned.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

status
string

Filter by status. Options: verified, pending, approved, rejected, all. Default: verified.

Example:
verified
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/sender-ids?status=verified" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": [
        {
            "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
            "sender_id": "EXOCLASS",
            "admin_status": "approved",
            "provider_status": "verified",
            "is_verified": true,
            "is_default": true,
            "rejection_reason": null,
            "message_count": 42,
            "created_at": "2026-01-01T10:00:00+00:00",
            "approved_at": "2026-01-01T12:00:00+00:00",
            "verified_at": "2026-01-01T14:00:00+00:00"
        },
        {
            "id": "9a7f2e5c-1234-5678-90ab-cdef12345679",
            "sender_id": "EXOSMS",
            "admin_status": "approved",
            "provider_status": "verified",
            "is_verified": true,
            "is_default": false,
            "rejection_reason": null,
            "message_count": 15,
            "created_at": "2026-01-02T10:00:00+00:00",
            "approved_at": "2026-01-02T11:00:00+00:00",
            "verified_at": "2026-01-02T13:00:00+00:00"
        }
    ]
}

Request New Sender ID

POST
https://send.exoclass.com
/api/v1/sender-ids
requires authentication

Submit a new sender ID request for approval. The sender ID will be created in pending status and must go through a two-stage approval process:

  1. Admin approval (manual review by ExoSend administrators)
  2. Provider verification (automatic verification with SMS provider)

Only after both stages can the sender ID be used for sending messages.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/sender-ids" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"sender_id\": \"EXOCLASS\"
}"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "sender_id": "EXOCLASS",
        "admin_status": "pending",
        "provider_status": "pending",
        "is_verified": false,
        "is_default": false,
        "created_at": "2026-01-03T14:30:00+00:00"
    },
    "message": "Sender ID request submitted. Awaiting approval from administrator."
}
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The given data was invalid",
        "details": {
            "sender_id": [
                "The sender id must be between 3 and 11 characters."
            ]
        }
    }
}

Set Default Sender ID

PATCH
https://send.exoclass.com
/api/v1/sender-ids/{id}/default
requires authentication

Set a verified sender ID as the default for your organization. Only verified sender IDs can be set as default. Automatically unsets any previously set default sender ID.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the sender ID.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request PATCH \
    "https://send.exoclass.com/api/v1/sender-ids/9a7f2e5c-1234-5678-90ab-cdef12345678/default" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": {
        "id": "9a7f2e5c-1234-5678-90ab-cdef12345678",
        "sender_id": "EXOCLASS",
        "is_verified": true,
        "is_default": true
    },
    "message": "Sender ID set as default"
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Sender ID not found"
    }
}
{
    "success": false,
    "error": {
        "code": "NOT_VERIFIED",
        "message": "Only verified sender IDs can be set as default. Current status: pending approval."
    }
}

Delete Sender ID

DELETE
https://send.exoclass.com
/api/v1/sender-ids/{id}
requires authentication

Delete a sender ID from your organization. Sender IDs with existing messages or set as default cannot be deleted.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
string
required

The UUID of the sender ID.

Example:
9a7f2e5c-1234-5678-90ab-cdef12345678
Example request:
curl --request DELETE \
    "https://send.exoclass.com/api/v1/sender-ids/9a7f2e5c-1234-5678-90ab-cdef12345678" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "success": true,
    "data": null,
    "message": "Sender ID deleted successfully"
}
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "Sender ID not found"
    }
}
{
    "success": false,
    "error": {
        "code": "IS_DEFAULT",
        "message": "Cannot delete the default sender ID. Set another as default first."
    }
}
{
    "success": false,
    "error": {
        "code": "HAS_MESSAGES",
        "message": "Cannot delete sender ID with existing messages",
        "details": {
            "message_count": 42
        }
    }
}

SMS Campaigns

APIs for creating, managing, and sending bulk SMS campaigns. Campaigns follow a lifecycle: draft -> sending/scheduled -> sent/completed/cancelled.

Create SMS Campaign

POST
https://send.exoclass.com
/api/v1/sms/campaigns
requires authentication

Create a new SMS campaign. The campaign will be in draft status unless scheduled_at is provided, in which case it will be set to scheduled status.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/sms/campaigns" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"b\",
    \"message_content\": \"n\",
    \"sender_id_id\": \"6b72fe4a-5b40-307c-bc24-f79acf9a1bb9\",
    \"target_list_ids\": [
        \"977e5426-8d13-3824-86aa-b092f8ae52c5\"
    ],
    \"contact_ids\": [
        \"d6fa562b-acd5-35ff-babb-d11194d3737b\"
    ],
    \"manual_phones\": [
        \"+36\"
    ],
    \"scheduled_at\": \"2052-03-28\",
    \"timezone\": \"Asia\\/Yekaterinburg\",
    \"batch_size\": 22,
    \"send_rate_per_minute\": 7
}"

List SMS Campaigns

GET
https://send.exoclass.com
/api/v1/sms/campaigns
requires authentication

Retrieve a paginated list of all SMS campaigns for your organization, sorted by newest first.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/sms/campaigns" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
Headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
    "message": "Unauthenticated."
}

Get SMS Campaign Details

GET
https://send.exoclass.com
/api/v1/sms/campaigns/{smsCampaign_id}
requires authentication

Retrieve full details of a specific SMS campaign including refreshed stats.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

smsCampaign_id
string
required

The ID of the smsCampaign.

Example:
019ca407-ed12-71fa-8020-ed1b6fefc081
Example request:
curl --request GET \
    --get "https://send.exoclass.com/api/v1/sms/campaigns/019ca407-ed12-71fa-8020-ed1b6fefc081" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
Headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
    "message": "Unauthenticated."
}

Send SMS Campaign

POST
https://send.exoclass.com
/api/v1/sms/campaigns/{smsCampaign_id}/send
requires authentication

Start sending a draft or scheduled campaign immediately.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

smsCampaign_id
string
required

The ID of the smsCampaign.

Example:
019ca407-ed12-71fa-8020-ed1b6fefc081
Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/sms/campaigns/019ca407-ed12-71fa-8020-ed1b6fefc081/send" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"

Pause SMS Campaign

POST
https://send.exoclass.com
/api/v1/sms/campaigns/{smsCampaign_id}/pause
requires authentication

Pause a campaign that is currently sending.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

smsCampaign_id
string
required

The ID of the smsCampaign.

Example:
019ca407-ed12-71fa-8020-ed1b6fefc081
Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/sms/campaigns/019ca407-ed12-71fa-8020-ed1b6fefc081/pause" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"

Cancel SMS Campaign

POST
https://send.exoclass.com
/api/v1/sms/campaigns/{smsCampaign_id}/cancel
requires authentication

Cancel a campaign that is sending, paused, or scheduled.

Headers

Authorization
Example:
Bearer {YOUR_API_TOKEN}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

smsCampaign_id
string
required

The ID of the smsCampaign.

Example:
019ca407-ed12-71fa-8020-ed1b6fefc081
Example request:
curl --request POST \
    "https://send.exoclass.com/api/v1/sms/campaigns/019ca407-ed12-71fa-8020-ed1b6fefc081/cancel" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"