Programmatic access to your Dueted workspace. A REST API over your leads, domains, conversations and messages, plus signed webhooks for the six events.
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.
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:writeA request missing the required scope returns 403 with a message naming the scope it needs.
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).
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.
GET /domains, POST /domains (name required), and GET/PATCH/DELETE /domains/{id}. Fields: name, status, ask, floor, bin_price, registrar, renewal, lander, listings.
Read-only. GET /conversations (filter with ?lead_id=) and GET /conversations/{id}. A conversation groups the messages of one email thread.
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 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.
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).
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.