MisarMisar Docs
MisarMailMisarBlogMisarReachMisarPostMisarDevMisarCoderMisarSEOMisar PlatformMisar SSO
API Reference

Analytics

Email performance metrics, campaign analytics, and custom event tracking

Analytics endpoints expose send metrics and engagement rates at both account and per-campaign level, and let you track custom conversion and purchase events. The /api/v1/analytics and /api/v1/track/* endpoints use API-key auth; the richer dashboard analytics (/analytics/*) use the logged-in session cookie.

Auth scopes: analytics reads metrics on /api/v1/analytics; tracking endpoints accept track, track:events / track:purchase, or analytics.

Plan gates on analytics features

  • Basic metrics (opens, clicks, bounces): all plans
  • 90-day history: Pro+
  • 365-day history + heatmaps: Max+
  • Ecommerce / revenue tracking (/track/purchase, /analytics/revenue): Max (ecommerce_tracking feature)
  • Report export and scheduled reports: Max

Rates returned by /api/v1/analytics are percentages (0–100). The session dashboard endpoints (/analytics/benchmark, etc.) return raw ratios (0–1) unless noted.

Account & campaign metrics

GET/mail/v1/analytics

One endpoint serves both aggregate and per-campaign metrics. Omit campaignId for account-level usage over the period; pass campaignId to get a single campaign's stats.

Query parameters

startDatestringquery

Start date, YYYY-MM-DD. Defaults to 30 days ago.

endDatestringquery

End date, YYYY-MM-DD. Defaults to today.

campaignIdUUIDquery

When set, returns stats for that one campaign instead of the account aggregate.

groupBystringquerydefault: day

Bucketing granularity — day, week, or month.

Response — account (no campaignId)

data.periodobject

Resolved { start, end } range.

data.emailUsageArray<object>

Daily rows: date, emails_sent_today, emails_sent_month.

data.campaignTotalsobject

Summed sent, opened, clicked, bounced, complained across campaigns in range.

data.ratesobject

openRate, clickRate, bounceRate (percentages, 0–100).

data.warningstring

Present only when more than 1000 campaigns matched and totals were truncated.

Response — campaign (with campaignId)

data.campaignobject

Campaign row: id, name, subject, status, from_email, total_recipients, total_sent, total_delivered, total_opened, total_clicked, total_bounced, total_complained, total_unsubscribed, scheduled_at, created_at, updated_at.

data.ratesobject

openRate, clickRate, bounceRate, complaintRate, unsubscribeRate (percentages, 0–100).

Request — account
curl "https://api.misar.io/mail/v1/analytics?startDate=2026-03-07&endDate=2026-04-06" \
  -H "Authorization: Bearer msk_YOUR_API_KEY"
200 — Account
{
  "success": true,
  "data": {
    "period": { "start": "2026-03-07", "end": "2026-04-06" },
    "emailUsage": [
      { "date": "2026-03-07", "emails_sent_today": 420, "emails_sent_month": 420 }
    ],
    "campaignTotals": {
      "sent": 12480, "opened": 4884, "clicked": 1221, "bounced": 270, "complained": 12
    },
    "rates": { "openRate": 39.13, "clickRate": 9.78, "bounceRate": 2.16 }
  }
}
Request — campaign
curl "https://api.misar.io/mail/v1/analytics?campaignId=9c1e2b7a-0d44-4f8a-9b1e-2c963f66afa6" \
  -H "Authorization: Bearer msk_YOUR_API_KEY"
200 — Campaign
{
  "success": true,
  "data": {
    "campaign": {
      "id":                 "9c1e2b7a-0d44-4f8a-9b1e-2c963f66afa6",
      "name":               "April Newsletter",
      "subject":            "Spring is here",
      "status":             "sent",
      "from_email":         "hello@yourdomain.com",
      "total_recipients":   5200,
      "total_sent":         5200,
      "total_delivered":    5096,
      "total_opened":       2038,
      "total_clicked":      510,
      "total_bounced":      104,
      "total_complained":   5,
      "total_unsubscribed": 18,
      "scheduled_at":       "2026-04-01T09:00:00Z",
      "created_at":         "2026-03-30T09:00:00Z",
      "updated_at":         "2026-04-01T10:00:00Z"
    },
    "rates": {
      "openRate": 39.19, "clickRate": 9.81, "bounceRate": 2.0,
      "complaintRate": 0.1, "unsubscribeRate": 0.35
    }
  }
}

Track a custom event

POST/mail/v1/track/event

Record a custom event tied to a contact by email. Useful for measuring downstream conversions from email clicks. Accepts scope track, track:events, or analytics.

Request body

emailstringbodyrequired

Email of the contact who triggered the event.

event_namestringbodyrequired

Event name (1–100 chars).

event_dataobjectbody

Arbitrary key-value metadata (defaults to {}).

sourcestringbody

Where the event originated (max 30 chars).

campaign_idUUIDbody

Campaign to associate the event with.

page_urlstringbody

URL where the event happened (valid URL, max 2048).

referrerstringbody

Referrer URL (valid URL, max 2048).

Response fields

successboolean

true when the event was recorded.

event_idstring | null

Identifier for the tracked event.

Request
curl -X POST https://api.misar.io/mail/v1/track/event \
  -H "Authorization: Bearer msk_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email":      "user@example.com",
    "event_name": "trial_started",
    "source":     "welcome_email",
    "event_data": { "plan": "pro" }
  }'
200 — OK
{ "success": true, "event_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7" }

Track a purchase event

POST/mail/v1/track/purchase

Record a purchase with revenue, attributed to the most recent clicked campaign or automation within the attribution window. Accepts scope track, track:purchase, or analytics, and requires the ecommerce_tracking plan feature. Amounts are in cents.

Request body

emailstringbodyrequired

Purchasing contact.

order_idstringbodyrequired

Your system's order ID (1–255). Deduplication key — (user, order_id) is unique.

total_centsnumberbodyrequired

Order total in cents (positive integer).

currencystringbodydefault: USD

ISO 4217 currency code (exactly 3 chars).

itemsarraybody

Line items (max 500), each { name, quantity, price_cents }price_cents in cents.

attribution_window_hoursnumberbodydefault: 72

Look-back window for click attribution (1–720 hours).

Response fields

successboolean

true when the purchase was recorded.

purchase_idstring | null

Identifier for the purchase row.

attributionobject

source, campaign_id, automation_id, and click_timestamp (any may be null if no click matched).

Request
curl -X POST https://api.misar.io/mail/v1/track/purchase \
  -H "Authorization: Bearer msk_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email":       "user@example.com",
    "order_id":    "order_12345",
    "total_cents": 9999,
    "currency":    "USD",
    "items": [
      { "name": "Pro Plan", "quantity": 1, "price_cents": 9999 }
    ]
  }'
200 — OK
{
  "success": true,
  "purchase_id": "b7c9e667-7425-40de-944b-e07fc1f90ae7",
  "attribution": {
    "source":          "campaign",
    "campaign_id":     "9c1e2b7a-0d44-4f8a-9b1e-2c963f66afa6",
    "automation_id":   null,
    "click_timestamp": "2026-04-01T09:30:00Z"
  }
}
Purchase tracking requires the Max plan (ecommerce_tracking feature). Blocked accounts receive 403 from enforcePlanLimit.

Benchmark against industry

GET/mail/analytics/benchmark

Compare your last-30-day metrics against industry averages. Cached for 1 hour. Uses session authentication.

Response fields

successboolean

true when the request succeeded.

cachedboolean

Whether the response came from cache.

dataobject

Comparison per metric (openRate, clickRate, bounceRate, unsubscribeRate), each with yours, industry, delta, and better (ratios 0–1). For open/click, better: true means above average; for bounce/unsubscribe it means below average.

Request
curl "https://api.misar.io/mail/analytics/benchmark" \
  -H "Cookie: sb-access-token=YOUR_SESSION"
200 — OK
{
  "success": true,
  "cached": false,
  "data": {
    "openRate":        { "yours": 0.31,  "industry": 0.251, "delta": 0.059,  "better": true },
    "clickRate":       { "yours": 0.04,  "industry": 0.028, "delta": 0.012,  "better": true },
    "bounceRate":      { "yours": 0.015, "industry": 0.02,  "delta": -0.005, "better": true },
    "unsubscribeRate": { "yours": 0.01,  "industry": 0.009, "delta": 0.001,  "better": false }
  }
}

Churn-risk contacts

GET/mail/analytics/churn-risk

Rule-based churn scoring for subscribed contacts. Returns the top 50 at-risk contacts, highest score first. Takes no query parameters. Uses session authentication.

Response fields

successboolean

true when the request succeeded.

cachedboolean

true when served from cache.

dataobject

A contacts array; each contact has id, email, first_name, last_name, last_engagement_at, emails_sent, emails_opened, churnScore (0–100, higher = more at risk), and daysSinceOpen (or null).

Request
curl "https://api.misar.io/mail/analytics/churn-risk" \
  -H "Cookie: sb-access-token=YOUR_SESSION"
200 — OK
{
  "success": true,
  "data": {
    "contacts": [
      {
        "id":                 "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "email":              "user@example.com",
        "first_name":         "Alex",
        "last_name":          "Doe",
        "last_engagement_at": "2026-01-10T00:00:00Z",
        "emails_sent":        24,
        "emails_opened":      2,
        "churnScore":         82,
        "daysSinceOpen":      47
      }
    ]
  }
}

Cohort analysis

GET/mail/analytics/cohorts

Retention by subscription month — each cohort is the contacts who subscribed in a given calendar month. Uses session authentication.

Query parameters

monthsnumberquerydefault: 6

Number of trailing months to include (1–24).

Response fields

successboolean

true when the request succeeded.

dataobject

A cohorts array; each cohort has cohortMonth, label, totalContacts, and periods — an array of { monthOffset, activeCount, retentionPct } (offsets 0, 1, 2, 3 → month / +30d / +60d / +90d).

Request
curl "https://api.misar.io/mail/analytics/cohorts?months=6" \
  -H "Cookie: sb-access-token=YOUR_SESSION"
200 — OK
{
  "success": true,
  "data": {
    "cohorts": [
      {
        "cohortMonth":   "2026-01",
        "label":         "Jan 2026",
        "totalContacts": 420,
        "periods": [
          { "monthOffset": 0, "activeCount": 420, "retentionPct": 100 },
          { "monthOffset": 1, "activeCount": 189, "retentionPct": 45 },
          { "monthOffset": 2, "activeCount": 160, "retentionPct": 38 },
          { "monthOffset": 3, "activeCount": 130, "retentionPct": 31 }
        ]
      }
    ]
  }
}
Cohort data requires Pro+ plan (90-day history).

Export analytics data

GET/mail/analytics/export

Export a report as a CSV download (Content-Disposition: attachment). Provide either a saved report_id or a report_type. Uses session authentication.

Query parameters

report_idUUIDquery

A saved report to export. Its stored report_type and filters are used.

report_typestringquery

One of campaign_performance, cohort_analysis, send_time_heatmap, engagement_funnel. Required if report_id is omitted.

date_fromstringquery

Start date, YYYY-MM-DD.

date_tostringquery

End date, YYYY-MM-DD.

Request
curl "https://api.misar.io/mail/analytics/export?report_type=campaign_performance&date_from=2026-01-01&date_to=2026-03-31" \
  -H "Cookie: sb-access-token=YOUR_SESSION" \
  -o report.csv
Report export requires Max plan.

Performance insights

GET/mail/analytics/insights

Rule-based insights about your email performance over the last 30 days. Takes no query parameters. Uses session authentication.

Response fields

successboolean

true when the request succeeded.

cachedboolean

true when served from cache.

dataobject

An insights array — each { type, title, description, value? } where type is positive, warning, or tip — plus bestDayByOpenRate (per-weekday open-rate breakdown).

Request
curl "https://api.misar.io/mail/analytics/insights" \
  -H "Cookie: sb-access-token=YOUR_SESSION"
200 — OK
{
  "success": true,
  "data": {
    "insights": [
      {
        "type": "positive",
        "title": "Tuesday sends perform best",
        "description": "Emails sent on Tuesday get ~40% higher open rates than other days. Schedule more campaigns on Tuesday."
      },
      {
        "type": "warning",
        "title": "Inactive contacts detected",
        "description": "1,240 subscribed contacts haven't opened an email in 90 days. Consider a win-back campaign or list cleanup.",
        "value": "1,240 contacts"
      }
    ],
    "bestDayByOpenRate": []
  }
}

Saved reports

GET/mail/analytics/reports

List saved report definitions. Uses session authentication. A POST to the same path creates a report (name, report_type, optional filters, schedule, is_public).

Response fields

successboolean

true when the request succeeded.

dataobject

A reports array; each report has id, name, report_type, filters, schedule, last_generated_at, is_public, public_token, created_at, and updated_at.

Request
curl "https://api.misar.io/mail/analytics/reports" \
  -H "Cookie: sb-access-token=YOUR_SESSION"
200 — OK
{
  "success": true,
  "data": {
    "reports": [
      {
        "id":                "rpt_abc123",
        "name":              "Monthly Campaign Summary",
        "report_type":       "campaign_performance",
        "filters":           { "dateFrom": "2026-05-01", "dateTo": "2026-05-31" },
        "schedule":          "monthly",
        "last_generated_at": "2026-05-01T09:00:00Z",
        "is_public":         false,
        "public_token":      null,
        "created_at":        "2026-04-01T09:00:00Z",
        "updated_at":        "2026-05-01T09:00:00Z"
      }
    ]
  }
}

report_type accepts campaign_performance, engagement_funnel, cohort_analysis, send_time_heatmap, growth, revenue, or deliverability. schedule is one of daily, weekly, monthly. Scheduled reports require the Max plan.

Revenue attribution

GET/mail/analytics/revenue

Which campaigns drove revenue. Requires the Max plan with ecommerce tracking. Uses session authentication. Revenue values are in cents.

Response fields

successboolean

true when the request succeeded.

cachedboolean

true when served from cache.

dataobject

totalRevenue (cents), revenueBySource (source → cents), topCampaigns (each { campaign_id, campaign_name, revenue, conversions }), and revenueTimeline (last 30 days as { date, revenue }).

Request
curl "https://api.misar.io/mail/analytics/revenue" \
  -H "Cookie: sb-access-token=YOUR_SESSION"
200 — OK
{
  "success": true,
  "data": {
    "totalRevenue": 1542050,
    "revenueBySource": { "campaign": 1200000, "automation": 342050 },
    "topCampaigns": [
      {
        "campaign_id":   "camp_abc123",
        "campaign_name": "Spring Sale",
        "revenue":       620000,
        "conversions":   31
      }
    ],
    "revenueTimeline": [
      { "date": "2026-04-01", "revenue": 82000 }
    ]
  }
}

Status codes

  • 200 — Metrics or report returned.
  • 400 — Validation failed or invalid JSON body.
  • 401 — Missing/invalid API key, or (session endpoints) not logged in.
  • 403 — API key lacks the required scope, or the plan does not include the feature.
  • 404 — Campaign or saved report not found.
  • 415Content-Type is not application/json (tracking POSTs).