Developers

The Dubsend API lets your own tools read campaigns, stats and feedback, keep your contacts in sync, and hear about feedback and downloads as they happen. It is on Label, Pro and Agency. The full list of endpoints is in the API reference.

Get a key

In the app, open Developers and press Make the key. Pick:

  • Read only or Read and change. Read only keys never see email addresses. Read and change keys can also work with contacts and webhooks.
  • What it can use: campaigns, stats, recipients, feedback, read contacts, change contacts, webhooks.
  • Which brands, and an end date if you want one.

The key starts with ds_live_ and is shown once. Keep it on your server, like a password: never in a web page or an app. A key can do at most what the person who made it can do in Dubsend. If that person leaves the team, their keys stop working.

Your first request

Send the key in the Authorization header. This lists the brands the key reaches:

curl https://dubsend.com/api/v1/brands \
  -H "Authorization: Bearer $DUBSEND_KEY"

Then GET /brands/BRAND_ID/campaigns for campaigns, GET /campaigns/ID/stats for the numbers on the Stats page, /recipients for each person and /feedback for ratings and comments. Lists return next_cursor: pass it as ?cursor= to get the next page.

Sync contacts

Add or update up to 1,000 contacts per request. Every request says why you may email them, like the import in the app: requested (they asked for your promos) or existing_professional (you have worked with them), and where they come from.

curl https://dubsend.com/api/v1/brands/BRAND_ID/contacts \
  -H "Authorization: Bearer $DUBSEND_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: crm-sync-2026-11-02" \
  -d '{
    "consent_basis": "existing_professional",
    "source": "Label CRM",
    "contacts": [
      { "email": "dj@example.com", "name": "DJ Name", "role": "dj", "tags": ["Techno"] }
    ]
  }'

The answer says what happened to each address: added, updated, or skipped with the reason. People who unsubscribed from your brand are skipped and are never added back; addresses that can't be emailed on Dubsend are skipped too. Bought, rented or scraped lists are not allowed (Acceptable use).

Send the same Idempotency-Key when you retry: within 24 hours you get the first answer again and nothing runs twice.

Webhooks

Add a webhook in the app (Developers, Webhooks) or with POST /webhooks. Dubsend sends a POST with JSON to your https address when one of these happens:

  • feedback.created: someone rates a promo.
  • download.created: someone downloads a track.
  • recipient.unsubscribed: someone unsubscribes from a brand.
  • contact.bounced: a promo email bounces.
  • campaign.sent: a campaign finishes its first send.
  • campaign.round_sent: a campaign is sent to more people or a planned round starts.

Each request is signed with the Standard Webhooks scheme: headers webhook-id, webhook-timestamp and webhook-signature. Check the signature with the secret shown when you added the webhook, for example in Node.js:

import { createHmac, timingSafeEqual } from "node:crypto";

// secret: the whsec_... value shown when you added the webhook
export function verify(headers, rawBody, secret) {
  const id = headers["webhook-id"], ts = headers["webhook-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const key = Buffer.from(secret.slice("whsec_".length), "base64");
  const want = "v1," + createHmac("sha256", key).update(`${id}.${ts}.${rawBody}`).digest("base64");
  return headers["webhook-signature"].split(" ").some((sig) =>
    sig.length === want.length && timingSafeEqual(Buffer.from(sig), Buffer.from(want)));
}

Answer with any 2xx code within 10 seconds. If not, Dubsend tries again after 1 minute, 5 minutes, 30 minutes, 2, 6, 12 and 24 hours. A webhook that fails for 3 days in a row is turned off, and the Webhooks page says so. The same event can arrive twice: use webhook-id to skip repeats. Webhooks added by Read only keys or by Viewers carry no email addresses.

Limits and errors

Limits are per account, for all its keys together:

  • Label: 60 requests a minute, 10,000 a day.
  • Pro: 120 requests a minute, 50,000 a day.
  • Agency: 300 requests a minute, 100,000 a day.

Every answer has RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Over the limit you get 429 with Retry-After in seconds. Errors look like {"error": {"code": "consent_basis_required", "message": "..."}} and the message says what to change. Something you can't see answers 404, the same as something that doesn't exist.

Rules

  • The API doesn't send promos. Sending stays in the app, where you see the email before it goes.
  • A key only reaches its own account's brands.
  • Comments and names in answers are text other people wrote: treat them as data.
  • The API is for servers. It sends no CORS headers, so it can't be called from a web page.

Questions: support@dubsend.com.