Skip to content

Email Gateway API Documentation

Email Gateway endpoints for managing transactional email sending through verified domains, including domain management, API keys, SMTP credentials, webhooks, and email delivery.

Add a Sender Domain

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.AddDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.adddomain
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainNameStringYesDomain name to add (e.g., example.com)
SubdomainStringNoCustom subdomain override (e.g., outbound). Only letters, numbers, and hyphens allowed (max 32 characters).
TrackPrefixStringNoCustom tracking prefix override (e.g., links). Only letters, numbers, and hyphens allowed (max 32 characters).
TrackMergeStringNoCustom tracking merge character (e.g., -).
TrackPrefixDisabledIntegerNoSet to 1 to disable the separate tracking subdomain. When disabled, tracking URLs use the sender (MFROM) domain instead.
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.adddomain",
    "SessionID": "your-session-id",
    "DomainName": "example.com",
    "Subdomain": "outbound",
    "TrackPrefix": "links"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "NewSenderDomainID": 123,
  "Domain": {
    "DomainID": 123,
    "SenderDomain": "example.com",
    "Status": "Approval Pending",
    "Options": {
      "LinkTracking": 1,
      "OpenTracking": 1,
      "UnsubscribeLink": 0,
      "CustomSubdomain": "outbound",
      "CustomTrackPrefix": "links"
    }
  }
}
json
{
  "Success": false,
  "ErrorCode": [1]
}
txt
0: Success
1: Missing required parameter (DomainName)
2: Invalid domain name format
3: Maximum sender domains limit reached for user
4: Invalid subdomain or track prefix value

Get Sender Domain Details

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.getdomain
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.getdomain",
    "SessionID": "your-session-id",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "Domain": {
    "DomainID": 123,
    "SenderDomain": "example.com",
    "Status": "Enabled",
    "Options": {
      "LinkTracking": 1,
      "OpenTracking": 1,
      "UnsubscribeLink": 0
    }
  }
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Update Sender Domain Settings

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.updatedomain
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
LinkTrackingIntegerNoEnable link tracking (1 = enabled, 0 = disabled)
OpenTrackingIntegerNoEnable open tracking (1 = enabled, 0 = disabled)
UnsubscribeLinkIntegerNoEnable unsubscribe link (1 = enabled, 0 = disabled)
HostingProviderStringNoHosting provider name
SubdomainStringNoCustom subdomain override (e.g., outbound). Only letters, numbers, and hyphens allowed (max 32 characters). Leave empty to reset to global default.
TrackPrefixStringNoCustom tracking prefix override (e.g., links). Only letters, numbers, and hyphens allowed (max 32 characters). Leave empty to reset to global default.
TrackMergeStringNoCustom tracking merge character (e.g., -).
TrackPrefixDisabledIntegerNoSet to 1 to disable the separate tracking subdomain. When disabled, tracking URLs use the sender (MFROM) domain instead. Set to 0 to re-enable.
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.updatedomain",
    "SessionID": "your-session-id",
    "DomainID": 123,
    "LinkTracking": 1,
    "OpenTracking": 1,
    "Subdomain": "outbound",
    "TrackPrefixDisabled": 1
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "Domain": {
    "DomainID": 123,
    "SenderDomain": "example.com",
    "Status": "Approval Pending",
    "Options": {
      "LinkTracking": 1,
      "OpenTracking": 1,
      "CustomSubdomain": "outbound",
      "TrackPrefixDisabled": true
    }
  },
  "SubdomainChanged": true
}
json
{
  "Success": false,
  "ErrorCode": 5
}
txt
0: Success
1: Missing required parameter (DomainID)
5: Domain not found or access denied
6: Invalid subdomain or track prefix value

Verify Sender Domain DNS Records

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.verifydomain
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.verifydomain",
    "SessionID": "your-session-id",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "Domain": {
    "DomainID": 123,
    "SenderDomain": "example.com",
    "Status": "Enabled"
  },
  "DNSVerificationResults": {
    "mail.example.com": ["CNAME", "target.example.com", true],
    "example.com": ["TXT", "v=spf1 include:example.com ~all", true]
  }
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Get All Sender Domains

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Returns every sender domain owned by the caller. By default the response shape is byte-for-byte identical to the pre-#1996 endpoint — useful for the legacy dashboard.

When WithCounts=1 is supplied, each row is additionally enriched with per-row API-key / SMTP / webhook counts (one SQL aggregation) and 7-day Sent / BounceRate / LastActivityAt stats from ES (one ES terms aggregation). This replaces the legacy 4×N pattern of calling emailgateway.getapis + emailgateway.getsmtps + emailgateway.getwebhooks + emailgateway.domainstats once per domain, which made the Overview unusable past ~20 domains.

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.getdomains
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
WithCountsMixedNoWhen truthy (1, '1', 'true', 'yes', true), each domain row is enriched with APIKeyCount, SMTPCount, WebhookCount, Sent7d, BounceRate7d, LastActivityAt. Any other value (missing, 0, 'false', garbage) → no enrichment, legacy shape preserved.

Enrichment field reference (only present when WithCounts=1):

FieldTypeSourceDefinition
APIKeyCountIntegerSQLCount of oempro_eg_api_keys rows for this domain with Status='Enabled'
SMTPCountIntegerSQLCount of oempro_eg_smtp_credentials rows for this domain with Status='Enabled'
WebhookCountIntegerSQLCount of oempro_eg_webhooks rows for this domain with Status='Enabled'
Sent7dIntegerESCount of accepted-by-oempro events for this domain in the last 7 days
BounceRate7dFloat (2dp)computedBounced / Sent × 100. Returns 0 when Sent7d is 0 (no divide-by-zero NaN)
LastActivityAtString or nullESMAX(logged-at) within the 7-day window as ISO 8601 UTC; null if no events
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.getdomains",
    "SessionID": "your-session-id"
  }'
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.getdomains",
    "SessionID": "your-session-id",
    "WithCounts": 1
  }'
json
{
  "Success": true,
  "Domains": [
    {
      "DomainID": "123",
      "SenderDomain": "mail.apex.com",
      "CreatedAt": "2026-04-01 10:00:00",
      "Status": "Enabled",
      "VerificationMeta": {"DNSRecords": []},
      "PolicyMeta": [],
      "Options": {"LinkTracking": 1, "OpenTracking": 1, "UnsubscribeLink": 0}
    }
  ]
}
json
{
  "Success": true,
  "Domains": [
    {
      "DomainID": "123",
      "SenderDomain": "mail.apex.com",
      "CreatedAt": "2026-04-01 10:00:00",
      "Status": "Enabled",
      "VerificationMeta": {"DNSRecords": []},
      "PolicyMeta": [],
      "Options": {"LinkTracking": 1, "OpenTracking": 1, "UnsubscribeLink": 0},
      "APIKeyCount": 1,
      "SMTPCount": 2,
      "WebhookCount": 2,
      "Sent7d": 184320,
      "BounceRate7d": 1.00,
      "LastActivityAt": "2026-05-15T18:42:11Z"
    }
  ]
}
txt
0: Success

Delete a Sender Domain

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.deletedomain
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID to delete
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.deletedomain",
    "SessionID": "your-session-id",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Clear Domain Email Queue

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.cleardomainqueue
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.cleardomainqueue",
    "SessionID": "your-session-id",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Get Domain Statistics

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.domainstats
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
StartDateStringNoStart date (Y-m-d format, default: 28 days ago)
EndDateStringNoEnd date (Y-m-d format, default: today)
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.domainstats",
    "SessionID": "your-session-id",
    "DomainID": 123,
    "StartDate": "2024-01-01",
    "EndDate": "2024-01-31"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "Stats": {
    "Sent": 1000,
    "Delivered": 950,
    "Bounced": 50,
    "Opened": 400,
    "Clicked": 150
  },
  "ComparisonStats": {
    "PreviousPeriod": {
      "Sent": 800,
      "Delivered": 760
    }
  },
  "TagStats": {
    "campaign1": {
      "Sent": 500,
      "Delivered": 475
    }
  }
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Get Account-Wide Statistics

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Returns cross-domain aggregate statistics (Sent / Delivered / Bounced / Opened / Clicked + rates) for the caller's email gateway domains in a single call. Replaces the N+1 pattern of looping emailgateway.domainstats once per sender domain. Per-domain rows are ordered by Sent descending; domains with no events in the period are zero-filled. The ComparisonTotals window is the same length as the requested period, ending the second before StartDate.

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.accountstats
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
StartDateStringNoStart date (Y-m-d format, default: 30 days ago)
EndDateStringNoEnd date (Y-m-d format, default: today). Clamped to >= StartDate
DomainIDsStringNoComma-separated list of sender domain IDs to scope the result to. IDs not owned by the caller are silently ignored. Omit to include all of the caller's gateway domains
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.accountstats",
    "SessionID": "your-session-id",
    "StartDate": "2024-01-01",
    "EndDate": "2024-01-31",
    "DomainIDs": "1,2,3"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "StartDate": "2024-01-01 00:00:00",
  "EndDate": "2024-01-31 23:59:59",
  "Totals": {
    "Sent": 232530,
    "Delivered": 226115,
    "Bounced": 1931,
    "Opened": 90636,
    "Clicked": 14261,
    "DeliveryRate": 97.24,
    "OpenRate": 38.99,
    "ClickRate": 6.14,
    "BounceRate": 0.83
  },
  "ComparisonTotals": {
    "Sent": 198400,
    "Delivered": 192100,
    "Bounced": 1820,
    "Opened": 74500,
    "Clicked": 11020,
    "DeliveryRate": 96.83,
    "OpenRate": 37.55,
    "ClickRate": 5.55,
    "BounceRate": 0.92
  },
  "PerDomain": [
    {
      "DomainID": 1,
      "SenderDomain": "mail.apex.com",
      "Sent": 184320,
      "Delivered": 178224,
      "Bounced": 1520,
      "Opened": 71890,
      "Clicked": 11420,
      "DeliveryRate": 96.69,
      "BounceRate": 0.82,
      "OpenRate": 39.0,
      "ClickRate": 6.19
    }
  ]
}
json
{
  "Success": false,
  "ErrorCode": 99998
}
txt
0: Success
99998: Authentication failure or session expired

Create API Key for Domain

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.addapi
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DescriptionStringYesDescription for the API key
DomainIDIntegerYesSender domain ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.addapi",
    "SessionID": "your-session-id",
    "Description": "Production API Key",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "NewAPIKeyID": 456,
  "APIKey": {
    "APIKeyID": 456,
    "APIKey": "eg_live_xxxxxxxxxxxx",
    "Description": "Production API Key",
    "DomainID": 123
  }
}
json
{
  "Success": false,
  "ErrorCode": [1, 2]
}
txt
0: Success
1: Missing required parameter (Description)
2: Missing required parameter (DomainID)
3: Domain not found or access denied

Get Domain API Keys

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.getapis
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.getapis",
    "SessionID": "your-session-id",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "APIKeys": [
    {
      "APIKeyID": 456,
      "APIKey": "eg_live_xxxxxxxxxxxx",
      "Description": "Production API Key",
      "DomainID": 123
    }
  ]
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Delete Domain API Key

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.deleteapi
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
APIKeyIDIntegerYesAPI Key ID to delete
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.deleteapi",
    "SessionID": "your-session-id",
    "APIKeyID": 456
  }'
json
{
  "Success": true,
  "ErrorCode": 0
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (APIKeyID)
2: API Key not found or access denied

Create SMTP Credentials for Domain

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.addsmtp
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.addsmtp",
    "SessionID": "your-session-id",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "NewSMTPID": 789,
  "SMTP": {
    "SMTPID": 789,
    "SMTPUsername": "smtp_user_xxx",
    "SMTPPassword": "generated_password",
    "SMTPHost": "smtp.example.com",
    "SMTPPorts": [25, 587, 2525]
  }
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Get Domain SMTP Credentials

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.getsmtps
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.getsmtps",
    "SessionID": "your-session-id",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "SMTPs": [
    {
      "SMTPID": 789,
      "SMTPUsername": "smtp_user_xxx",
      "SMTPHost": "smtp.example.com",
      "SMTPPorts": [25, 587, 2525]
    }
  ]
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Delete SMTP Credentials

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.deletesmtp
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
SMTPIDIntegerYesSMTP credentials ID to delete
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.deletesmtp",
    "SessionID": "your-session-id",
    "SMTPID": 789
  }'
json
{
  "Success": true,
  "ErrorCode": 0
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (SMTPID)
2: SMTP credentials not found or access denied

Reset SMTP Password

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.resetsmtppassword
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
SMTPIDIntegerYesSMTP credentials ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.resetsmtppassword",
    "SessionID": "your-session-id",
    "SMTPID": 789
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "SMTP": {
    "SMTPID": 789,
    "SMTPUsername": "smtp_user_xxx",
    "SMTPPassword": "new_generated_password"
  }
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (SMTPID)
2: SMTP credentials not found or access denied

Create Webhook for Domain

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

The WebhookURL is validated to prevent SSRF attacks: the scheme must be http or https, and the host cannot be localhost, 127.0.0.1, ::1, or end in .local. These checks live in the API itself (since #1999) so direct API callers can't bypass them by skipping the legacy UI flow.

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.addwebhook
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
EventStringYesEvent type. Possible values: delivery, bounce, open, click, unsubscribe, complaint
WebhookURLStringYesWebhook URL to receive event notifications. Must be an http/https URL whose host is not localhost / 127.0.0.1 / ::1 / *.local
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.addwebhook",
    "SessionID": "your-session-id",
    "DomainID": 123,
    "Event": "delivery",
    "WebhookURL": "https://example.com/webhooks/email-events"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "NewWebhookID": 999
}
json
{
  "Success": false,
  "ErrorCode": 6,
  "ErrorMessage": "Webhook URL must be a valid HTTP or HTTPS URL."
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Missing required parameter (Event)
3: Invalid event type
4: Domain not found or access denied
5: Missing required parameter (WebhookURL)
6: WebhookURL is not a valid HTTP or HTTPS URL (e.g. ftp:// or malformed)
7: WebhookURL host is forbidden (localhost, 127.0.0.1, ::1, or *.local)

Get Domain Webhooks

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.getwebhooks
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.getwebhooks",
    "SessionID": "your-session-id",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "SigningKey": "whsec_xxxxxxxxxxxx",
  "Webhooks": [
    {
      "WebhookID": 999,
      "Event": "delivery",
      "WebhookURL": "https://example.com/webhooks/email-events"
    }
  ]
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Delete Domain Webhook

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.deletewebhook
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
WebhookIDIntegerYesWebhook ID to delete
DomainIDIntegerYesSender domain ID
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.deletewebhook",
    "SessionID": "your-session-id",
    "WebhookID": 999,
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0
}
json
{
  "Success": false,
  "ErrorCode": 4
}
txt
0: Success
1: Missing required parameter (WebhookID)
2: Missing required parameter (DomainID)
3: Domain not found or access denied
4: Webhook not found or access denied

Create Webhook (Public API)

POST /api/v1/webhooks

API Usage Notes

  • Authentication required: Bearer token
  • Rate limit: 100 requests per 60 seconds
  • Legacy endpoint access via /api.php is also supported

Request Body Parameters:

ParameterTypeRequiredDescription
SenderAPIKeyStringYesAPI key for the sender domain (Bearer token)
EventStringYesEvent type: delivered, bounced, opened, clicked, unsubscribed, complained
WebhookURLStringYesWebhook URL to receive event notifications
bash
curl -X POST https://example.com/api/v1/webhooks \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eg_live_xxxxxxxxxxxx" \
  -d '{
    "Event": "delivered",
    "WebhookURL": "https://example.com/webhooks/email-events"
  }'
json
{
  "NewWebhookID": 999
}
json
{
  "Errors": [
    {"Code": 3, "Message": "Invalid Event value"}
  ]
}
txt
2: Event is missing
3: Invalid event type or invalid webhook URL
5: WebhookURL is missing
13: Invalid SenderAPIKey
429: Too many requests

Get Webhooks (Public API)

GET /api/v1/webhooks

API Usage Notes

  • Authentication required: Bearer token
  • Rate limit: 100 requests per 60 seconds
  • Legacy endpoint access via /api.php is also supported

Request Body Parameters:

ParameterTypeRequiredDescription
SenderAPIKeyStringYesAPI key for the sender domain (Bearer token)
bash
curl -X GET https://example.com/api/v1/webhooks \
  -H "Authorization: Bearer eg_live_xxxxxxxxxxxx"
json
{
  "Webhooks": [
    {
      "WebhookID": 999,
      "Event": "delivered",
      "WebhookURL": "https://example.com/webhooks/email-events"
    }
  ]
}
json
{
  "Errors": [
    {"Code": 13, "Message": "Invalid SenderAPIKey"}
  ]
}
txt
2: Invalid user account
13: Invalid SenderAPIKey
429: Too many requests

Delete Webhook (Public API)

DELETE /api/v1/webhooks

API Usage Notes

  • Authentication required: Bearer token
  • Rate limit: 100 requests per 60 seconds
  • Legacy endpoint access via /api.php is also supported

Request Body Parameters:

ParameterTypeRequiredDescription
SenderAPIKeyStringYesAPI key for the sender domain (Bearer token)
WebhookIDIntegerYesWebhook ID to delete
bash
curl -X DELETE https://example.com/api/v1/webhooks \
  -H "Authorization: Bearer eg_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "WebhookID": 999
  }'
json
{}
json
{
  "Errors": [
    {"Code": 4, "Message": "Invalid WebhookID"}
  ]
}
txt
1: WebhookID is missing
2: Invalid user account
4: Invalid WebhookID
13: Invalid SenderAPIKey
429: Too many requests

Get Email Events

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Cross-domain queries

DomainID is optional. When a DomainID is supplied, events are scoped to that single domain and ownership is verified against the authenticated user. When DomainID is omitted, the query spans every sender domain owned by the authenticated user. Tenant isolation is inherent: events are indexed per-user in Elasticsearch (eg-events-u<UserID>-<date>) and the query always filters by user-id regardless of whether a DomainID is provided.

Note that the public variant (emailgateway.getevents.public) still requires DomainID because it is authenticated by a domain-scoped API key.

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.getevents
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerNoSender domain ID to scope the query to. Omit to return events across all of the authenticated user's sender domains.
StartFromIntegerYesStarting record index for pagination
RetrieveCountIntegerYesNumber of records to retrieve (max 100)
StartDateStringNoStart date filter (Y-m-d format)
EndDateStringNoEnd date filter (Y-m-d format)
EventStringNoFilter by event type (delivery, bounce, open, click, etc.)
QueryStringNoSearch query string
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.getevents",
    "SessionID": "your-session-id",
    "DomainID": 123,
    "StartFrom": 0,
    "RetrieveCount": 50,
    "Event": "delivery"
  }'
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.getevents",
    "SessionID": "your-session-id",
    "StartFrom": 0,
    "RetrieveCount": 50,
    "Event": "delivery"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "TotalRecords": 150,
  "Events": [
    {
      "event": "delivery",
      "timestamp": 1640000000,
      "message": {
        "headers": {
          "from": "sender@example.com",
          "to": "recipient@example.com",
          "subject": "Test Email"
        }
      }
    }
  ]
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
2: Domain not found or access denied (only when DomainID is supplied)
4: Missing required parameter (StartFrom)
5: Missing required parameter (RetrieveCount)

Get Email Events (Public API)

GET /api/v1/events

API Usage Notes

  • Authentication required: Bearer token
  • Rate limit: 100 requests per 60 seconds
  • Legacy endpoint access via /api.php is also supported

Request Body Parameters:

ParameterTypeRequiredDescription
SenderAPIKeyStringYesAPI key for the sender domain (Bearer token)
StartFromIntegerNoStarting record index for pagination (default: 0)
RetrieveCountIntegerNoNumber of records to retrieve (default: 5, max 100)
StartDateIntegerNoStart date filter (Unix timestamp)
EndDateIntegerNoEnd date filter (Unix timestamp)
EventStringNoFilter by event type
MessageIDStringNoFilter by message ID
bash
curl -X GET https://example.com/api/v1/events \
  -H "Authorization: Bearer eg_live_xxxxxxxxxxxx" \
  -d '{
    "StartFrom": 0,
    "RetrieveCount": 50,
    "Event": "delivery"
  }'
json
{
  "TotalRecords": 150,
  "Events": [
    {
      "Event": "delivery",
      "LoggedAt": 1640000000,
      "Message": {
        "Headers": {
          "From": "sender@example.com",
          "To": "recipient@example.com",
          "Subject": "Test Email"
        }
      }
    }
  ]
}
json
{
  "Errors": [
    {"Code": 13, "Message": "Invalid SenderAPIKey"}
  ]
}
txt
1: Missing SenderAPIKey
2: Invalid sender domain
4: Missing StartFrom
5: Missing RetrieveCount
13: Invalid SenderAPIKey
429: Too many requests

Get Aggregated Event Statistics

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.aggrevents
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID
StartDateStringNoStart date filter (Y-m-d format)
EndDateStringNoEnd date filter (Y-m-d format)
AggregatedFieldStringNoField to aggregate by
AggregateSizeIntegerNoNumber of aggregation buckets
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.aggrevents",
    "SessionID": "your-session-id",
    "DomainID": 123,
    "StartDate": "2024-01-01",
    "EndDate": "2024-01-31"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "AggBuckets": [
    {
      "key": "delivery",
      "doc_count": 1000
    },
    {
      "key": "bounce",
      "doc_count": 50
    }
  ]
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or access denied

Send Email via API

POST /api/v1/email

API Usage Notes

  • Authentication required: Bearer token
  • Rate limit: 100 requests per 60 seconds
  • Legacy endpoint access via /api.php is also supported

Request Body Parameters:

ParameterTypeRequiredDescription
SenderAPIKeyStringYesAPI key for the sender domain (Bearer token)
SubjectStringYesEmail subject line
ContentTypeStringYesContent type: html or plain
HTMLContentStringConditionalHTML email content (required if ContentType is html)
PlainContentStringConditionalPlain text email content (required if ContentType is plain)
FromObjectYesSender information:
ToArrayConditionalArray of recipients: [{name, email}] (required unless TargetListID is set)
CCArrayNoArray of CC recipients: [{name, email}]
BCCArrayNoArray of BCC recipients: [{name, email}]
ReplyToArrayNoArray of reply-to addresses: [{name, email}]
TagsArrayNoArray of custom tags for tracking
HeadersObjectNoCustom email headers as key-value pairs
TrackLinksStringNoEnable link tracking: true or false
TrackOpensStringNoEnable open tracking: true or false
SendAtIntegerNoSchedule send time (Unix timestamp)
AttachmentsArrayNoArray of attachments: [{filename, content, type, disposition, contentid}]
TemplateIDIntegerNoEmail template ID to use
TargetListIDIntegerNoSend to all subscribers in a list
ListIDIntegerNoList ID for subscriber context
SubscriberIDIntegerNoSubscriber ID for personalization
JourneyIDIntegerNoJourney ID for tracking
ActionIDIntegerNoJourney action ID for tracking
bash
curl -X POST https://example.com/api/v1/email \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eg_live_xxxxxxxxxxxx" \
  -d '{
    "Subject": "Welcome to Our Service",
    "ContentType": "html",
    "HTMLContent": "<h1>Welcome!</h1><p>Thank you for signing up.</p>",
    "From": {
      "name": "John Doe",
      "email": "john@example.com"
    },
    "To": [
      {
        "name": "Jane Smith",
        "email": "jane@example.com"
      }
    ]
  }'
json
{
  "MessageID": "550e8400-e29b-41d4-a716-446655440000"
}
json
{
  "Errors": [
    {"Code": 8, "Message": "Missing Subject"}
  ]
}
txt
1: Missing SenderAPIKey
2: Invalid DomainID or invalid user account
3: From parameter is missing or invalid
8: Missing Subject or To email address
9: Missing ContentType
10: Missing HTMLContent
11: Missing PlainContent
12: Invalid or deactivated user account
13: Invalid SenderAPIKey
14: Email address is in the suppression list
15: Invalid TemplateID
16: Invalid TargetListID
17: Email sending limit reached
18: Recipient name or email address is missing
19: Recipient email address is invalid
20: There is no recipient set or count exceeds limit
21-22: CC email validation errors
23: Invalid from email address format
24-26: BCC email validation errors
27: BCC count exceeds limit
28-30: Reply-To email validation errors
31: Reply-To count exceeds limit
32: Domain is not activated
34: User account is not verified
35: Invalid ListID
36: Invalid SubscriberID
37: Invalid JourneyID
38: Invalid ActionID
429: Email send rate limit exceeded

Send Email via SMTP Relay

POST /api.php

API Usage Notes

  • Authentication required: Admin API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)
  • This is an internal endpoint used by the SMTP relay server

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.smtprelay
AdminAPIKeyStringYesAdmin API key for authentication
SMTPUsernameStringYesSMTP username for authentication
SMTPPasswordStringYesSMTP password for authentication
UUIDStringNoUnique message identifier
MailFromStringNoMAIL FROM envelope address
RcptToStringNoRCPT TO envelope addresses (comma-separated)
SubjectStringNoEmail subject line
RawEmailStringNoRaw email content (RFC 822 format)
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.smtprelay",
    "AdminAPIKey": "your-admin-key",
    "SMTPUsername": "smtp_user_xxx",
    "SMTPPassword": "smtp_password"
  }'
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.smtprelay",
    "AdminAPIKey": "your-admin-key",
    "SMTPUsername": "smtp_user_xxx",
    "SMTPPassword": "smtp_password",
    "UUID": "550e8400-e29b-41d4-a716-446655440000",
    "MailFrom": "sender@example.com",
    "RcptTo": "recipient@example.com",
    "Subject": "Test Email",
    "RawEmail": "From: sender@example.com..."
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "SMTPUsername": "smtp_user_xxx",
  "SMTPPassword": "smtp_password"
}
json
{
  "Success": true,
  "ErrorCode": 0,
  "SMTPResponse": "250 2.0.0 Ok: queued",
  "SMTPUsername": "smtp_user_xxx",
  "SMTPPassword": "smtp_password"
}
json
{
  "Success": false,
  "SMTPResponse": "500 5.0.0 AUTH ERROR",
  "ErrorCode": 3
}
txt
0: Success
1: Missing SMTPUsername
2: Missing SMTPPassword
3: Invalid SMTP credentials
4: Invalid sender domain
5: Sender domain is not active
6: Invalid user account
7: User is not trusted or not enabled
8: Recipient email address is suppressed

Get All Sender Domains for PowerMTA Configuration

POST /api/v1/sender.domains

API Usage Notes

  • Authentication required: Admin API Key
  • Rate limit: 100 requests per 60 seconds
  • Legacy endpoint access via /api.php is also supported

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringNoAPI command: sender.domains (only required for legacy endpoint)
AdminAPIKeyStringNoAdmin API key for authentication (only required for legacy endpoint)
DomainsResponseFormatStringNoResponse format: json, powermta-bounce-domains, powermta-relay-domains (default: json)
bash
curl -X POST https://example.com/api/v1/sender.domains \
  -H "Content-Type: application/json" \
  -d '{
    "DomainsResponseFormat": "json"
  }'
json
{
  "Success": true,
  "Domains": [
    "example.com",
    "another.com",
    "third.com"
  ]
}
json
{
  "Success": false,
  "ErrorCode": 1,
  "ErrorText": "Invalid DomainsResponseFormat"
}
txt
0: Success
1: Invalid DomainsResponseFormat (must be json, powermta-bounce-domains, or powermta-relay-domains)

Check Inbound Relay Domain Authorization

GET /api/v1/inbound-relay-domain-check

API Usage Notes

  • Authentication required: Bearer token (Admin API Key)
  • This endpoint is designed for MX server integration to validate relay domains
  • Returns HTTP status codes to indicate relay authorization
  • Legacy endpoint access via /api.php is also supported

Request Body Parameters:

ParameterTypeRequiredDescription
DomainStringYesDomain name to check for relay authorization (can be full email address)
bash
curl -X GET "https://example.com/api/v1/inbound-relay-domain-check?domain=example.com" \
  -H "Authorization: Bearer your-admin-api-key"
json
{
  "Success": true,
  "RelayDomain": "example.com"
}
json
{
  "Errors": [
    {
      "Code": 1,
      "Message": "Authentication failed. Invalid admin API key."
    }
  ]
}
json
{}
txt
200: Relay allowed - domain is authorized for relay
403: Temporary error - authentication failed
500: Relay access denied - domain is not authorized
txt
1: Authentication failed - Invalid admin API key

Get Recipient Domain Statistics

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.recipientdomainstats
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID (used to verify user ownership)
RecipientToDomainStringYesRecipient domain to filter by (e.g., gmail.com)
StartDateStringNoStart date (Y-m-d format, default: 28 days ago)
EndDateStringNoEnd date (Y-m-d format, default: today)
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.recipientdomainstats",
    "SessionID": "your-session-id",
    "DomainID": 123,
    "RecipientToDomain": "gmail.com",
    "StartDate": "2026-01-01",
    "EndDate": "2026-02-11"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "SummaryStats": [
    {
      "Status": "Sent",
      "TotalEmails": 1523,
      "AvgDeliverySeconds": 4.32,
      "MinDeliverySeconds": 0,
      "MaxDeliverySeconds": 187
    },
    {
      "Status": "Failed",
      "TotalEmails": 42,
      "AvgDeliverySeconds": 12.58,
      "MinDeliverySeconds": 1,
      "MaxDeliverySeconds": 95
    }
  ],
  "DeliverySpeedHistogram": {
    "Sent": [
      { "DeliveryBucket": "< 1s", "EmailCount": 312, "Percentage": 20.49 },
      { "DeliveryBucket": "1-5s", "EmailCount": 845, "Percentage": 55.48 },
      { "DeliveryBucket": "5-10s", "EmailCount": 200, "Percentage": 13.13 },
      { "DeliveryBucket": "10-30s", "EmailCount": 100, "Percentage": 6.57 },
      { "DeliveryBucket": "30-60s", "EmailCount": 40, "Percentage": 2.63 },
      { "DeliveryBucket": "1-5m", "EmailCount": 20, "Percentage": 1.31 },
      { "DeliveryBucket": "5-10m", "EmailCount": 4, "Percentage": 0.26 },
      { "DeliveryBucket": "> 10m", "EmailCount": 2, "Percentage": 0.13 }
    ],
    "Failed": [
      { "DeliveryBucket": "1-5s", "EmailCount": 30, "Percentage": 71.43 },
      { "DeliveryBucket": "5-10s", "EmailCount": 12, "Percentage": 28.57 }
    ]
  }
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID or RecipientToDomain)
2: Domain not found or access denied

Export Events as CSV

GET /api.php   POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)
  • Response is text/csv; charset=utf-8 (streamed), not JSON. The dispatcher's JSON wrapping is bypassed.

Streams the email-gateway event log as CSV. Accepts the same filters as emailgateway.getevents but bypasses the 100-row browse cap (hard cap at 10,000 rows). Designed to be embedded directly in a browser download link — when the user clicks "Export CSV", the browser streams the file to disk.

Data is fetched from Elasticsearch in chunks of 1,000 rows; each chunk is flushed to the client immediately, so the loop is cancelable mid-download (closing the browser tab terminates the export before the next ES round-trip).

Response headers:

  • Content-Type: text/csv; charset=utf-8
  • Content-Disposition: attachment; filename="transactional-events-YYYY-MM-DD.csv"
  • X-Octeth-Export-Total: <int> — total matching events reported by ES.
  • X-Octeth-Export-Truncated: 1 — present only when Total > 10000; the CSV body contains the first 10,000 rows.
  • X-Octeth-Export-Limit: 10000 — present only when truncated.

CSV columns: Time (ISO 8601 UTC), Event, MessageID, From, To, Subject, Domain, SMTPCode. The file begins with a UTF-8 BOM so Excel opens it with the correct encoding. Address-like cells starting with =, +, -, @, tab, or carriage return are prefixed with a single quote to neutralize spreadsheet formula injection.

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.exportevents
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerNoScope to a single sender domain. Omit (or pass 0) to export across all of the caller's gateway domains
EventStringNoFilter by event type. Possible values: same as emailgateway.geteventsaccepted, rejected, delivered, bounced, opened, clicked, unsubscribed, complained, accepted-by-oempro, accepted-by-mta, rejected-by-oempro, rejected-by-mta
MessageIDStringNoFilter by message-id (takes precedence over Query when both are supplied)
QueryStringNoFree-text search across message metadata (subject, from, to, IP, MX host, SMTP response, etc.). Ignored when MessageID is supplied
StartDateStringNoStart date (Y-m-d strict). Defaults to 30 days ago. Invalid formats fall back to the default
EndDateStringNoEnd date (Y-m-d strict). Defaults to today. Clamped to >= StartDate
bash
# Browser-friendly GET — drop this into an <a href> or window.location:
curl -OJ -G https://example.com/api.php \
  --data-urlencode 'Command=emailgateway.exportevents' \
  --data-urlencode 'SessionID=your-session-id' \
  --data-urlencode 'DomainID=123' \
  --data-urlencode 'Event=bounced' \
  --data-urlencode 'StartDate=2026-01-01' \
  --data-urlencode 'EndDate=2026-01-31'
text
Time,Event,MessageID,From,To,Subject,Domain,SMTPCode
2026-01-31T18:42:11Z,bounced,bb1a701c-dcf0-4948-81eb-62726da0d67d,sender@apex.com,"Recipient <recipient@example.com>","Welcome to Apex",example.com,550
2026-01-31T18:41:55Z,bounced,162a101e-0c78-491a-9403-94dad8a3e1ca,sender@apex.com,"recipient2@example.org",,example.org,553
...
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success (CSV streamed)
2: DomainID supplied but not owned by the caller

Regenerate the Webhook Signing Key for a Domain

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Generates a fresh per-domain HMAC-SHA256 signing key, stores it atomically against the domain row, and returns it once. Subsequent calls to emailgateway.getwebhooks for the same domain return the new key, and outgoing webhook payloads from that domain are signed with it.

Backwards compatibility: until you call this endpoint for a given domain, that domain continues to sign and verify webhooks with the legacy installation-wide secret (md5(OEMPRO_PASSWORD_SALT . LICENSE_KEY), formatted as XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX). Existing integrations that haven't rotated are entirely unaffected by the rollout of this endpoint. Once you rotate a domain, the consumer of that domain's webhooks must update its verification key — every other domain's consumer keeps working unchanged.

The new key format is a 64-character uppercase hex string (256 bits of entropy from random_bytes(32)). It's shown once in the response and stored in the SigningKey column of the sender-domain row. There's no way to retrieve it later other than via getwebhooks for the same domain.

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.regeneratesigningkey
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesThe sender domain to rotate. Must be owned by the caller
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.regeneratesigningkey",
    "SessionID": "your-session-id",
    "DomainID": 123
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "SigningKey": "7F94D1EF4F798E4E1F306F06DC3DF317424D60C91B2C4DC7F11D13A8D1B1C5FC"
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or not owned by the caller
3: Rotation failed — the UPDATE matched zero rows (typically because the domain was deleted between the ownership check and the rotation). No key was persisted; safe to retry.

List Top Recipient Domains for a Sender Domain

POST /api.php   GET /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Returns a leaderboard of the recipient domains (e.g. gmail.com, yahoo.com, outlook.com) for emails sent from a single sender domain over a date range. Built as a single ES terms aggregation on message.to-domain with per-bucket Sent / Failed / Sending counts and SMTP-session delivery-time statistics. New capability — the legacy domain_recipients.php view required the user to type a recipient domain manually before any data was shown.

Counts semantics:

  • Sent = events where event = "accepted-by-mta" (recipient MTA acknowledged the message)
  • Failed = events where event ∈ {"bounced", "rejected-by-mta", "rejected-by-oempro"}
  • Sending = max(Total − Sent − Failed, 0), where Total is the count of accepted-by-oempro events. Represents messages that entered the gateway but haven't reached a terminal state yet.

Delivery-time fields (AvgDeliverySec, MinDeliverySec, MaxDeliverySec) come from delivery-status.session-seconds on accepted-by-mta events — the SMTP session duration recorded per delivery. Returns null when the bucket has no accepted-by-mta events. Rows are sorted by Sent desc.

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.listrecipientdomains
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID. Must be owned by the caller
StartDateStringNoStart date (Y-m-d strict). Defaults to 30 days ago. Invalid formats fall back to the default
EndDateStringNoEnd date (Y-m-d strict). Defaults to today. Clamped to >= StartDate
LimitIntegerNoMaximum number of recipient-domain rows. Default 50, clamped to [1, 1000]
bash
curl -G https://example.com/api.php \
  --data-urlencode 'Command=emailgateway.listrecipientdomains' \
  --data-urlencode 'SessionID=your-session-id' \
  --data-urlencode 'DomainID=123' \
  --data-urlencode 'StartDate=2026-04-01' \
  --data-urlencode 'EndDate=2026-04-30' \
  --data-urlencode 'Limit=20'
json
{
  "Success": true,
  "ErrorCode": 0,
  "StartDate": "2026-04-01 00:00:00",
  "EndDate": "2026-04-30 23:59:59",
  "Limit": 20,
  "RecipientDomains": [
    {
      "Domain": "gmail.com",
      "Sent": 11554,
      "Failed": 172,
      "Sending": 3,
      "AvgDeliverySec": 0.05,
      "MinDeliverySec": 0,
      "MaxDeliverySec": 1.0
    },
    {
      "Domain": "yahoo.com",
      "Sent": 4881,
      "Failed": 64,
      "Sending": 0,
      "AvgDeliverySec": 0.08,
      "MinDeliverySec": 0,
      "MaxDeliverySec": 2.0
    }
  ]
}
json
{
  "Success": false,
  "ErrorCode": 2
}
txt
0: Success
1: Missing required parameter (DomainID)
2: Domain not found or not owned by the caller

Atomically Replace a Domain API Key

POST /api.php

API Usage Notes

  • Authentication required: User API Key
  • Required permissions: EmailGateway.ManageDomain
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Atomically rotates the API key for a sender domain. Hard-deletes every prior row for the (UserID, DomainID) slot and inserts a new Enabled key — all inside a single MySQL transaction.

Kills the race the legacy "delete then create" flow had against the uk_user_domain_status (UserID, DomainID, Status) unique constraint, which would occasionally fail with "the slot may still be reserved in the database" when the two calls overlapped. Response shape mirrors emailgateway.addapi exactly, so callers can migrate by changing the Command name only. If the domain has no existing key the DELETE is a no-op and behaviour is identical to addapi.

Trade-off — the prior key row (including its Description and CreatedAt) is removed entirely, not soft-deleted. Audit-trail callers that need history should record it externally before invoking this endpoint.

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: emailgateway.replaceapi
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
DomainIDIntegerYesSender domain ID. Must be owned by the caller
DescriptionStringYesDescription for the new key (same semantics as emailgateway.addapi)
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "emailgateway.replaceapi",
    "SessionID": "your-session-id",
    "DomainID": 123,
    "Description": "Rotated 2026-05-16"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "NewAPIKeyID": 92,
  "APIKey": {
    "APIKeyID": "92",
    "UserID": "1",
    "DomainID": "123",
    "CreatedAt": "2026-05-16 04:26:31",
    "APIKey": "4D196964-B909FDD7-134A4E29-6B0E923E",
    "Description": "Rotated 2026-05-16",
    "Status": "Enabled",
    "Options": []
  }
}
json
{
  "Success": false,
  "ErrorCode": 3
}
txt
0: Success
1: Missing required parameter (Description)
2: Missing required parameter (DomainID)
3: Domain not found or not owned by the caller
4: Atomic rotate failed — the transaction rolled back; no key was persisted. Safe to retry.

Any questions? Contact us.