Developers

API & webhooks

Programmatic access to your Dueted workspace. A REST API over your leads, domains, conversations and messages, plus signed webhooks for the six events.

Authentication

Every request carries an API key created in Settings → API keys (owner only). The secret is shown once, prefixed dtd_live_. Send it as a bearer token:

curl https://app.dueted.link/api/v1/leads \
  -H "Authorization: Bearer dtd_live_xxx"

Keys are stored hashed (sha256) and can be revoked at any time. The base URL is https://app.dueted.link/api/v1.

Scopes

Each key holds a subset of scopes. A :write scope implies :read on the same resource.

leads:read      leads:write
domains:read    domains:write
conversations:read
messages:read   messages:write

A request missing the required scope returns 403 with a message naming the scope it needs.

Pagination

List endpoints take ?limit (1–200, default 50) and ?offset. Responses wrap the data:

{ "data": [ ... ], "limit": 50, "offset": 0, "total": 128 }

Order with ?order= (e.g. created_at.desc).

Leads

GET /leads — list (filter with ?status=). POST /leads — create (domain and company required). GET/PATCH/DELETE /leads/{id}.

# create a lead
curl -X POST https://app.dueted.link/api/v1/leads \
  -H "Authorization: Bearer dtd_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"domain":"GenoFoundry.com","company":"LifeFoundry","site":"life-foundry.com"}'

Writes go through an allowlist: you can set the lead fields (status, notes, ask_price, offer, contacts, …) but never id or workspace_id.

Domains

GET /domains, POST /domains (name required), and GET/PATCH/DELETE /domains/{id}. Fields: name, status, ask, floor, bin_price, registrar, renewal, lander, listings.

Conversations

Read-only. GET /conversations (filter with ?lead_id=) and GET /conversations/{id}. A conversation groups the messages of one email thread.

Messages

GET /messages (filter with ?conversation_id= or ?lead_id=). POST /messages logs a message record (lead_id and body required). Note: posting does not send email — outbound mail goes through the app's guarded send path.

Errors

Errors are JSON with an error string and a standard status: 400 bad request, 401 missing/invalid key, 403 missing scope, 404 not found, 405 read-only resource.

Webhooks

Register an endpoint in Settings → Integrations & webhooks and subscribe to any of the six events: reply, mention, assignment, inquiry, offer, domain_sold. Each delivery is a POST:

POST your-endpoint
X-Dueted-Event: reply
X-Dueted-Delivery: <uuid>
X-Dueted-Signature: sha256=<hmac>

{ "event": "reply", "data": { ... }, "delivery_id": "<uuid>" }

Verify the signature by recomputing HMAC-SHA256 over the raw body with your webhook secret (the same scheme Stripe and GitHub use):

const expected = "sha256=" +
  crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
if (expected !== req.headers["x-dueted-signature"]) reject();

Failed deliveries retry with backoff (1m → 5m → 30m → 2h → 6h, up to 6 attempts).

Slack & Discord

For Slack or Discord you do not need to write a receiver: paste an incoming-webhook URL when adding the webhook and pick Slack or Discord. Dueted formats a rich message (title, fields, an "Open in Dueted" link) for each event. No-code tools like Zapier and Make connect via the REST API plus a generic webhook.

Ready to build?

Create a workspace, then make a key in Settings → API keys.

Start free