Skip to main content

API reference

Activity data API

Access email activity and engagement data to understand email behavior and deliverability.

Get email activity

GET/v1/activity/{email}

Retrieve engagement activity data for a specific email address.

Response
{
  "success": true,
  "data": {
    "email": "user@example.com",
    "email_hash": "973dfe463ec85785f5f95af5ba3906ee...",
    "activity": {
      "level": "active",
      "score": 78,
      "last_activity_at": "2026-01-28T15:30:00Z",
      "engagement": {
        "open_count": 45,
        "click_count": 12,
        "reply_count": 2
      },
      "deliverability": {
        "bounce_count": null,
        "complaint_count": null
      },
      "confidence": 80,
      "data_points": 18
    },
    "credits_used": 0.5
  }
}

When no activity data exists for an email, activity.level is unknown with zeroed engagement metrics and a message field explaining that no data is available.

deliverability.bounce_count and deliverability.complaint_count are null for every address today. Kawaa does not currently receive a bounce or complaint feed, so null means not measured — read it as “we have no bounce or complaint data for this address”, never as “this address has never bounced”. Both fields carry a number once the signal is available.

Batch activity lookup

POST/v1/activity/batch

Look up activity data for multiple emails at once (up to 100 per request).

Request
{
  "emails": [
    "user1@example.com",
    "user2@example.com"
  ]
}
Response
{
  "success": true,
  "data": {
    "results": [
      {
        "email": "user1@example.com",
        "email_hash": "6f4b1c...",
        "activity": {
          "level": "active",
          "score": 78,
          "last_activity_at": "2026-01-28T15:30:00Z",
          "engagement": { "open_count": 45, "click_count": 12, "reply_count": 2 },
          "deliverability": { "bounce_count": null, "complaint_count": null },
          "confidence": 80,
          "data_points": 18
        }
      },
      {
        "email": "user2@example.com",
        "email_hash": "a91e2d...",
        "activity": {
          "level": "unknown",
          "score": 0,
          "last_activity_at": null,
          "engagement": { "open_count": 0, "click_count": 0, "reply_count": 0 },
          "deliverability": { "bounce_count": null, "complaint_count": null },
          "confidence": 0,
          "data_points": 0,
          "message": "No activity data available for this email"
        }
      }
    ],
    "total": 2,
    "credits_used": 0.5
  }
}

Domain activity

GET/v1/activity/domain/{domain}

Get the engagement the activity network has recorded across an entire domain.

Response
{
  "success": true,
  "data": {
    "domain": "example.com",
    "reputation_score": null,
    "reputation_grade": null,
    "activity": {
      "total_events": 2,
      "total_opens": 1,
      "total_clicks": 1
    },
    "last_updated_at": "2026-01-13T01:41:35.752Z",
    "credits_used": 1
  }
}

reputation_score and reputation_grade are null for every domain today — Kawaa does not currently compute a domain reputation score, and reports null rather than a 0 that would read as the worst possible reputation on a 0–100 scale.

Inside activity, a counter is present only when that event type has actually been recorded for the domain — an absent counter means never recorded, not zero. When nothing at all has been recorded, activity is empty, last_updated_at is null, and a message field says so.

Safe retries with Idempotency-Key

Paid activity lookups accept an optional Idempotency-Key header. Use a unique token of 1–255 printable ASCII characters with no spaces for each logical lookup, then keep it unchanged when retrying after a timeout or lost response.

Safe retry
curl "https://api.kawaa.com/v1/activity/user@example.com" \
  -H "X-Api-Key: ev_your_api_key" \
  -H "Idempotency-Key: 6f1c2a4e-3b7d-4e0a-9c11-2d8f5a7b9e01"
The header works on GET /v1/activity/{email}, POST /v1/activity/batch, and GET /v1/activity/domain/{domain}. For 24 hours, an exact repeat returns the stored result with credits_used: 0 and idempotent_replay: true. Reusing a key with different input returns 409 IDEMPOTENCY_KEY_CONFLICT before any charge. Requests without the header retain the ordinary one-request/one-charge behavior. Safe replay requires an internal receipt containing the submitted input and result. The receipt has a 24-hour expiration and cannot be replayed after that window; storage lifecycle deletion is asynchronous. Kawaa does not expose the receipt as a job or include it in activity analytics.

Credits

  • 0.5 credits per single email activity lookup (GET /v1/activity/{email})
  • 0.25 credits per email in a batch lookup (POST /v1/activity/batch, max 100 valid addresses of 254 characters each)
  • 1 credit per domain activity lookup (GET /v1/activity/domain/{domain})
  • Credits are charged per request, including when no activity data is found
  • If a lookup fails internally after the charge, the credits are refunded automatically

Engagement levels

LevelDescriptionCriteria
activeRecently engagedEngagement within the last 30 days
inactiveFading engagementNo engagement in 30-90 days
dormantLong-term unengagedNo engagement in 90+ days
unknownNo data availableInsufficient tracked activity

Data sources

Activity data is built from engagement your own Kawaa tracking observes:

  • • Tracking pixels from email campaigns
  • • Click tracking from email links

Activity is therefore participation-dependent: an address Kawaa has never seen engage returns an empty record rather than an inferred one, and coverage grows as you send with tracking enabled.

Privacy: All activity data is anonymized and aggregated. We never share individual recipient data with third parties.