API & MCP

Respondent invites API

Respondent invites let your own systems invite known people to an interview. Create a personal link for a customer with their email or account ID attached, send it however you like, and their answers are tied to that customer from the start.

You need a Pro, Business or Enterprise plan and an API key. For keys and authentication, see the API overview.

To read the results, use the Conversations API: each conversation carries its invite and the identities you attached.

These endpoints are older than the rest of the API and keep their original names: they call a project an agent (agentId) and use camelCase parameters.

HTTP
POST /api/v1/respondent-invites

Each request creates one link for one respondent in one project. Diaform also creates the conversation immediately and attaches the identities you send, so the results are linked to that person from the start.

Request body#

FieldTypeRequiredRules
agentIdstringYesProject ID (UUID) in the key's organization
identitiesarrayYes1 to 10 items, one per type.
identities[].typestringYesUp to 64 characters: lowercase letters, numbers, _ and -, starting with a letter or number. Uppercase is converted to lowercase.
identities[].valuestringYes1 to 512 characters after trimming. An email value must be a valid email address and is stored in lowercase.
organizationIdstringNoIf you send it, it must match the key's organization
send_emailbooleanNotrue emails the link to the invite's email identity and sends one reminder after 3 days if the respondent hasn't finished. Default false.

When you send send_email, the response has an email object: { "status": "sent" }, { "status": "failed" }, or { "status": "skipped", "reason": "..." }. The invite is created in every case. Reasons are no_email, unsubscribed, not_published, no_usage, monthly_limit (your plan's invitation emails for the month are used up), answered, already_sent, in_progress, plan and not_found. See Identifying respondents for what the email contains.

Common types are email, name, identifier, user_id and account_id. Any type that follows the rules works.

Example#

curl -X POST "https://diaform.io/api/v1/respondent-invites" \
  -H "Authorization: Bearer $DIAFORM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "b8acb3ab-1f3d-4a7e-a846-b7f493f86b6d",
    "identities": [
      { "type": "email", "value": "alex@acme.com" },
      { "type": "account_id", "value": "acct_4821" }
    ]
  }'

Response#

JSON
{
  "organization_id": "4d6ecdb4-8543-4adf-ae65-1f24106d5474",
  "agent_id": "b8acb3ab-1f3d-4a7e-a846-b7f493f86b6d",
  "agent_name": "Onboarding interviews",
  "invite": {
    "id": "3a4f49c7-b8f4-4c44-8f74-fd8e4277c3e4",
    "created_at": "2026-05-07T12:00:00.123456+00:00",
    "status": "pending",
    "opened_at": null,
    "completed_at": null,
    "conversation_id": "0f8d43a2-6df9-49c8-bf5d-fd2b6ec2d9ee",
    "identities": [
      {
        "id": "71138f36-d16a-41f8-8a1f-65b9b8d483e3",
        "created_at": "2026-05-07T12:00:00.123456+00:00",
        "conversation_id": "0f8d43a2-6df9-49c8-bf5d-fd2b6ec2d9ee",
        "source": "owner",
        "identity_type": "email",
        "value": "alex@acme.com",
        "metadata": {}
      },
      {
        "id": "120feee2-a10e-4b9a-af8e-a54d4dd672a1",
        "created_at": "2026-05-07T12:00:00.123456+00:00",
        "conversation_id": "0f8d43a2-6df9-49c8-bf5d-fd2b6ec2d9ee",
        "source": "owner",
        "identity_type": "account_id",
        "value": "acct_4821",
        "metadata": {}
      }
    ],
    "url": "https://acme.diaform.io/c/b8acb3ab-1f3d-4a7e-a846-b7f493f86b6d?invite=dia_resp_pCaJHykjUYBKZdkbVUtbyZRMC3yFzm246SK2K8lw"
  }
}
FieldDescription
invite.idInvite ID. Webhooks send it as respondent.invite_id.
invite.statuspending, opened or completed
invite.conversation_idThe conversation created for this respondent
invite.identitiesThe identities you sent, each with source: "owner"
invite.urlThe link to send. It uses your verified custom domain if you have one. null once the invite is completed.
  1. Created. The invite is pending and its conversation is invited.
  2. Opened. When the respondent opens the link, both become opened. The conversation moves to started once they reply.
  3. Resumed. If the respondent leaves and comes back through the same link, they continue the same conversation.
  4. Ended. When the conversation ends, whether completed or cancelled, the invite becomes completed and the link stops working.

The project must be published for the link to open. Links work for both Public link and Invite-only links projects. On public projects, the normal link keeps working too. See Identifying respondents.

Older conversations endpoint#

HTTP
GET /api/v1/respondent-conversations

This endpoint lists a project's conversations and still works, so existing integrations don't need to change. For new work, use List conversations, which adds filters, transcripts and simpler paging.

ParameterRequiredDescription
agentIdYesProject ID
limitNo1 to 100. Default 50.
statusNoinvited, opened, started, completed or cancelled
cursorNonextCursor.created_at from the previous page
cursorIdNonextCursor.id from the previous page

It returns conversations (each with conversation_id, created_at, status, respondent_email, metadata, identities, summary and invite) and nextCursor, an object with created_at and id, or null on the last page. Send those two values back as cursor and cursorId.

URL-encode cursor. Its timestamp contains a +, which must be sent as %2B. A raw + is read as a space and the request fails with 400. curl --data-urlencode and URLSearchParams encode it for you.

Errors#

Errors return JSON with an error message and a code, as in the rest of the API. A 400 also includes details.fieldErrors, which names the field that failed.

JSON
{
  "error": "Invalid request",
  "code": "invalid_request",
  "details": {
    "formErrors": [],
    "fieldErrors": {
      "identities": ["Add at least one respondent identity."]
    }
  }
}
StatuscodeCause
400invalid_requestA field or query parameter is missing or invalid
401unauthorizedThe Authorization header is missing, isn't Bearer dia_org_live_..., or the key was revoked
403forbiddenYour organization isn't on Pro, Business or Enterprise, or organizationId doesn't match the key
404not_foundagentId isn't a project in the key's organization
500internal_errorAn error occurred on Diaform's side. Try again.

Limits#

These two endpoints have no rate limit. Each invite takes up to 10 identities (one per type), and each organization can have up to 10 API keys.