Kwikly LogoDocumentation

Operator guide for the Instantly.ai ↔ HubSpot sync, dashboard, and webhooks.

Open dashboard

Overview

This app keeps Instantly outreach activity on the matching HubSpot contact so sales and ops can see sends, replies, and opt-outs in one place. Instantly (and HubSpot, for exclusions) POST events to this app. The app looks up the contact by email, writes timeline activity, and updates lead status when the event calls for it.

Email activity

Sent mail and replies land on the HubSpot timeline.

Lead status

Replies, not-interested, and opt-outs update prospecting status.

Compliance

Opt-outs and HubSpot exclusion lists stop further Instantly outreach.

Contacts must already exist in HubSpot. If there is no match, the event is skipped and recorded as a “contact not found” — the app does not create HubSpot contacts.

How it works

  1. Step 1

    Event fires

    Instantly or a HubSpot workflow sends a webhook to this app.

  2. Step 2

    Request is verified

    Signatures or the shared webhook secret are checked before any work runs.

  3. Step 3

    HubSpot is updated

    The contact is found by email, then engagements and properties are written.

  4. Step 4

    Failures retry

    Failed events go on a retry queue. Persistent failures show on the dashboard.

What gets synced

TriggerHubSpot resultprospecting_status
Email sentSent email engagement; last Instantly contact dateUnchanged
Reply received (interested)Incoming email engagementWarm Lead
Reply received (not interested)Incoming email engagementCold Lead
Lead not interestedTimeline noteCold Lead
Opt-outNote; optional HubSpot static list addOpted out of Email/SMS Outreach
HubSpot exclusion listNo HubSpot write — email is added to Instantly exclusionsUnchanged

Required HubSpot properties: prospecting_status and last_instantlyai_contact_date.

Dashboard

The monitoring dashboard is at /dashboard. Unlock it with the DASHBOARD_API_KEY environment variable. The key is stored in session storage for this browser tab only.

What to watch

  • Success rate should stay high (typically above 98%).
  • A growing retry queue usually means HubSpot or Instantly is failing or rate-limiting.
  • Contacts not found means Instantly emailed someone who is not in HubSpot yet.
  • Recent Errors lists the last 50 webhook and retry failures, with correlation IDs.

Metric cards

  • Last 24 hours / last hour — inbound webhook volume.
  • Success rate and average processing time — how cleanly events complete.
  • Active retries — items still waiting to be replayed.
  • Audit events — security and skip events written to the audit log.

Webhooks

Point Instantly (Settings → Webhooks) and the HubSpot exclusion workflow at these URLs. Instantly’s webhook secret must match WEBHOOK_SECRET.

Email Sent

Instantly

https://<your-app>/api/webhooks/instantly/email-sent

Logs a sent-email engagement on the HubSpot contact and updates last Instantly contact date.

HMAC signature (x-instantly-signature or x-signature)

Reply Received

Instantly

https://<your-app>/api/webhooks/instantly/reply-received

Logs the inbound reply. Sets Warm Lead when sentiment is interested; Cold Lead when not interested.

HMAC signature (x-instantly-signature or x-signature)

Opt-Out

Instantly

https://<your-app>/api/webhooks/instantly/opt-out

Writes an opt-out note, sets prospecting status to Opted out of Email/SMS Outreach, and adds the contact to the HubSpot blocklist when configured.

HMAC signature (x-instantly-signature or x-signature)

Lead Not Interested

Instantly

https://<your-app>/api/webhooks/instantly/lead-not-interested

Writes a note and sets prospecting status to Cold Lead.

HMAC signature (x-instantly-signature or x-signature)

Lead Status Changed

Instantly

https://<your-app>/api/webhooks/instantly/lead-status-changed

Writes a note and sets prospecting status to Cold Lead.

HMAC signature (x-instantly-signature or x-signature)

Exclusion List

HubSpot

https://<your-app>/api/webhooks/hubspot/exclusion-list

Adds the contact email to Instantly’s global exclusion list so they are not emailed again.

HubSpot signature, or WEBHOOK_SECRET request header

Duplicate deliveries are ignored. Email addresses are encrypted at rest and masked in logs.

Operations

JobSchedulePurpose
GET /api/cron/retryEvery 5 minutesReplays failed events (up to 3 attempts, exponential backoff capped at 8 minutes).
GET /api/cron/purgeDaily 03:00 UTCDeletes webhook, audit, activity, and exclusion logs older than 90 days.
GET /api/healthOn demandConfirms the app can reach Postgres. No auth required.

Cron routes require CRON_SECRET as x-cron-secret or a Bearer token. After retries are exhausted, alerts can fire to Slack or n8n when those webhook URLs are set.

Security

  • Instantly webhooks are verified with HMAC-SHA256 against WEBHOOK_SECRET.
  • HubSpot exclusion webhooks use HubSpot’s signature (preferred via HUBSPOT_CLIENT_SECRET) or the shared WEBHOOK_SECRET header.
  • Dashboard APIs require x-api-key: DASHBOARD_API_KEY.
  • Contact emails are encrypted at rest with AES-256-GCM (PII_ENCRYPTION_KEY) and redacted in application logs.

Troubleshooting

SymptomWhat to check
Signature verification failedInstantly’s webhook secret must match WEBHOOK_SECRET.
401 on HubSpot exclusion webhookSend WEBHOOK_SECRET as a request header, or configure HubSpot signature verification.
Contact not foundCreate the contact in HubSpot before Instantly emails them. The integration will not create contacts.
Retry queue growingCheck HubSpot and Instantly status, API keys, and rate limits. Retries run every 5 minutes.
Dashboard will not unlockUse the current DASHBOARD_API_KEY. A 401 means the key does not match.

For stack traces, use Sentry and Vercel runtime logs. Correlation IDs on the dashboard error table match those log entries.