Skip to main content

Overview

Sendkit is a cold email sending platform. The integration is two-way: RevyOps ingests email send/reply/bounce activity and lead status changes from Sendkit via webhook, and pushes RevyOps’ unified Do-Not-Contact list out to Sendkit’s blacklist. Unlike some sequencer integrations, Sendkit setup needs both an API key (so RevyOps can register the webhook and read your tags) and the webhook itself — RevyOps registers the webhook for you automatically as part of setup.

Prerequisites

  • An active Sendkit account
  • A Sendkit API key (Sendkit Settings → API Keys → Create API Key)
  • Your RevyOps client_id (find it under Settings → Workspace)
  • An admin role in RevyOps — connecting the integration and triggering the DNC push are admin-only actions

Setup

1

Open the Sendkit integration panel

In RevyOps, open Integrations from the sidebar (admin only) and select Sendkit.
2

Enter your API key

Paste your Sendkit API key and click Verify & Connect. RevyOps checks it against Sendkit’s GET /tags endpoint before continuing.
3

Webhook is registered automatically

Once the key verifies, RevyOps calls Sendkit’s webhook API on your behalf and creates a webhook named RevyOps, subscribed to:email.sent, email.opened, email.clicked, email.replied, email.bounced, email.unsubscribed, email.positive_reply, lead.tag_changedIf automatic registration fails (for example, an API key without webhook permissions), RevyOps falls back to a manual step: copy the URL below and add it yourself under Sendkit Settings → Webhooks → Add Webhook.
4

Classify your tags

RevyOps pulls your existing Sendkit tags and lets you mark each one Interested, Blocked (Do Not Contact), both, or leave it unclassified. This mapping controls what happens when a lead.tag_changed event arrives — see Status and Tag Mapping below.
RevyOps subscribes to email.opened and email.clicked when it creates the webhook, but neither event is currently processed — RevyOps acknowledges and ignores them. Only the events listed below result in a record or status change.

Agency Setup (Global Webhook)

For agencies managing multiple client workspaces off a single Sendkit account, use the global webhook instead of connecting each client separately:
This one webhook receives every event and routes each one to the right client workspace by matching the event’s campaignName against the campaign keywords you’ve assigned to each client (configured on the Campaign Mapping page — case-sensitive substring match). A client only receives events this way if Sendkit is checked as a mapped integration for that client and at least one keyword matches.
Routing depends entirely on campaignName being present in the event payload — an event that arrives without one isn’t routed to any client and is dropped. If you’re using the agency-level webhook and a particular event type from Sendkit never seems to arrive, confirm that event type actually includes a campaign name.
If a client has both the agency-level webhook configured for Sendkit and its own per-client webhook still registered in Sendkit, the per-client webhook silently no-ops on direct hits from Sendkit — events for that client are only processed once, via the agency route.

Events and what they do

Auto-map labels to status is on by default but configurable — turning it off keeps the email-level disposition/label change but stops it from overwriting the contact’s status field directly (RevyOps still records the mapped value as a sendkit_status custom field on the contact instead). Any other event type Sendkit might send is acknowledged with 200 OK and dropped without further processing.
Because of how the mapping logic works today, email.positive_reply is stored as an OUTBOUND-type email record rather than INBOUND, even though it represents a reply. If you’re inspecting raw email records by type, keep this in mind.

Status and Tag Mapping

Sendkit tags are matched against three lists you configure from the integration panel (Edit Statuses), each pulled from Sendkit’s /tags endpoint:
  • Interested — a lead.tag_changed event with a matching tag sets the email’s disposition to that tag’s name (and the contact’s status too, if auto-mapping is on)
  • Other / labeled — sets the email’s non-interested disposition (label) to the tag’s name
  • Blocked (Do Not Contact) — marks the contact Do Not Contact
Interested and Blocked are set independently in the classifier, so the same tag can be marked both — in that case a matching lead.tag_changed event does both: it sets the Interested disposition/status and marks the contact Do Not Contact. A tag that’s neither Interested nor Blocked is treated as “Other” and only sets the label.

Do-Not-Contact Sync

Inbound (Sendkit → RevyOps): an email.unsubscribed event, or a lead.tag_changed event whose tag is in your Blocked list, marks the matching contact (by email) Do Not Contact in RevyOps — this also marks every other contact record that shares the same underlying person (e.g. the same lead with multiple email addresses). This direction requires a contact with that email to already exist in RevyOps; if none is found, the event is logged and dropped. Outbound (RevyOps → Sendkit): RevyOps unifies Do-Not-Contact signals from every connected platform into one suppression list. Whenever a contact is newly marked DNC anywhere in RevyOps — regardless of which integration triggered it — RevyOps pushes that contact’s email to Sendkit’s POST /dnc endpoint in real time (batched in groups of up to 5,000 when multiple contacts are marked at once). If the DNC mark originated from a Sendkit event itself, Sendkit is skipped to avoid pushing it right back. Removing a contact from Do Not Contact in RevyOps similarly issues a DELETE /dnc to take them back off Sendkit’s blacklist. All of the above — inbound handling, the outbound real-time push, and the historical backfill below — share one toggle: Cross-Platform Do Not Contact Sync in the Sendkit panel, on by default. Turning it off disables DNC sync in every direction for Sendkit. A separate Sync Historical DNC List button backfills contacts that were already marked Do Not Contact in RevyOps before Sendkit was connected — it queues a background job that pushes them to Sendkit’s blacklist in the same batches of 5,000, retrying automatically on rate limits. It also respects the toggle above: if DNC sync is off, the backfill is skipped rather than run.

Data Mapped

Sendkit webhooks don’t include a company field, so company data is not populated from this integration.

Custom Fields

Any entries under data.lead.customFields in the webhook payload are attached to the resulting email record as custom fields — this applies to standard send/reply/bounce events and email.positive_reply, not to lead.tag_changed.

Troubleshooting

RevyOps couldn’t create the webhook through the Sendkit API — usually because the API key doesn’t have permission to manage webhooks. Add the webhook manually in Sendkit under Settings → Webhooks using the URL shown in the setup panel, then continue.
RevyOps checks the key against GET /tags. A 401/403 response marks it invalid — regenerate the key in Sendkit and re-enter it.
Only tags you’ve explicitly classified as Interested or Blocked in the integration panel trigger an action — an unclassified tag is logged and ignored. Open Edit Statuses and confirm the tag is assigned to one of the lists, and that auto-map labels to status is enabled if you expect the contact’s status field (not just the email disposition) to change.If the tag is classified correctly and still nothing changes, check whether RevyOps has any email history for that lead at all. Both lead.tag_changed and email.positive_reply look for an existing inbound email to attach the status/disposition to; if none exists, RevyOps tries to fall back to the lead’s most recent outbound email to build one — but if there’s no outbound email on file for that contact either, the update is silently skipped.
Check whether the client has both a direct per-client Sendkit webhook and agency-level mapping enabled for Sendkit on the Campaign Mapping page. The per-client webhook should no-op automatically in that case — if you’re still seeing duplicates, confirm the client isn’t also registered under a second Sendkit workspace pointed at both URLs.
Confirm the Sendkit API key is valid and the integration shows as configured, and that Cross-Platform Do Not Contact Sync is toggled on for Sendkit. For contacts marked DNC before the integration was connected, use Sync Historical DNC List to backfill them.