Qualifying Interviews

Send qualifying questionnaires to prospects, capture leads from a public URL, and seed product configurations from the answers.

All Qualifying Interviews endpoints require JWT authentication via the Authorization: Bearer <token> header. Some endpoints require Admin role.

Core Endpoints

GET /interview-templates List interview templates
JWT Required

List all interview templates for the current organization.

Response

List of interview templates

{
    "data": [
        {
            "id": 1,
            "organization_id": 1,
            "name": "Foxit PDF SDK Qualification",
            "slug": "foxit-pdf-sdk",
            "public_slug": "...",
            "lead_capture_enabled": true,
            "pages": [
                {}
            ],
            "questions": [
                {}
            ],
            "branding": {},
            "thank_you": {},
            "hints": {},
            "created_at": "2026-01-15T09:30:00.000000Z",
            "updated_at": "2026-01-15T09:30:00.000000Z"
        }
    ]
}

Code Examples

curl -X GET "https://crm.revorbit.com/api/interview-templates" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
const response = await fetch(
  "https://crm.revorbit.com/api/interview-templates",
  {
    method: "GET",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
    }
  }
);
const data = await response.json();
POST /interview-templates Create interview template
Admin Required

Create a new interview template. Templates are JSON-driven with pages, questions, conditional logic, and field-mapping hints for configurator seeding.

Request Body

NameTypeRequiredDescription
name string Required
slug string Required
public_slug string Optional Nullable
lead_capture_enabled boolean Optional
pages array[object] Required
questions array[object] Required
branding object Optional
thank_you object Optional
hints object Optional

Response

Template created

{
    "id": 1,
    "organization_id": 1,
    "name": "Foxit PDF SDK Qualification",
    "slug": "foxit-pdf-sdk",
    "public_slug": "...",
    "lead_capture_enabled": true,
    "pages": [
        {}
    ],
    "questions": [
        {}
    ],
    "branding": {},
    "thank_you": {},
    "hints": {},
    "created_at": "2026-01-15T09:30:00.000000Z",
    "updated_at": "2026-01-15T09:30:00.000000Z"
}

Code Examples

curl -X POST "https://crm.revorbit.com/api/interview-templates" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "...",
    "slug": "...",
    "public_slug": "...",
    "lead_capture_enabled": true,
    "pages": [
        {}
    ],
    "questions": [
        {}
    ],
    "branding": {},
    "thank_you": {},
    "hints": {}
}'
const response = await fetch(
  "https://crm.revorbit.com/api/interview-templates",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
      "Content-Type": "application/json"
    },
    body: JSON.stringify(
      {
          "name": "...",
          "slug": "...",
          "public_slug": "...",
          "lead_capture_enabled": true,
          "pages": [
              {}
          ],
          "questions": [
              {}
          ],
          "branding": {},
          "thank_you": {},
          "hints": {}
      }
    )
  }
);
const data = await response.json();
GET /interview-templates/{id} Get interview template
JWT Required

Path Parameters

NameTypeRequiredDescription
id integer Required Resource ID

Response

Template details

{
    "id": 1,
    "organization_id": 1,
    "name": "Foxit PDF SDK Qualification",
    "slug": "foxit-pdf-sdk",
    "public_slug": "...",
    "lead_capture_enabled": true,
    "pages": [
        {}
    ],
    "questions": [
        {}
    ],
    "branding": {},
    "thank_you": {},
    "hints": {},
    "created_at": "2026-01-15T09:30:00.000000Z",
    "updated_at": "2026-01-15T09:30:00.000000Z"
}

Code Examples

curl -X GET "https://crm.revorbit.com/api/interview-templates/{id}" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
const response = await fetch(
  "https://crm.revorbit.com/api/interview-templates/{id}",
  {
    method: "GET",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
    }
  }
);
const data = await response.json();
PUT /interview-templates/{id} Update interview template
Admin Required

Path Parameters

NameTypeRequiredDescription
id integer Required Resource ID

Request Body

NameTypeRequiredDescription
name string Required
slug string Required
public_slug string Optional Nullable
lead_capture_enabled boolean Optional
pages array[object] Required
questions array[object] Required
branding object Optional
thank_you object Optional
hints object Optional

Code Examples

curl -X PUT "https://crm.revorbit.com/api/interview-templates/{id}" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "...",
    "slug": "...",
    "public_slug": "...",
    "lead_capture_enabled": true,
    "pages": [
        {}
    ],
    "questions": [
        {}
    ],
    "branding": {},
    "thank_you": {},
    "hints": {}
}'
const response = await fetch(
  "https://crm.revorbit.com/api/interview-templates/{id}",
  {
    method: "PUT",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
      "Content-Type": "application/json"
    },
    body: JSON.stringify(
      {
          "name": "...",
          "slug": "...",
          "public_slug": "...",
          "lead_capture_enabled": true,
          "pages": [
              {}
          ],
          "questions": [
              {}
          ],
          "branding": {},
          "thank_you": {},
          "hints": {}
      }
    )
  }
);
const data = await response.json();
DELETE /interview-templates/{id} Delete interview template
Admin Required

Path Parameters

NameTypeRequiredDescription
id integer Required Resource ID

Code Examples

curl -X DELETE "https://crm.revorbit.com/api/interview-templates/{id}" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
const response = await fetch(
  "https://crm.revorbit.com/api/interview-templates/{id}",
  {
    method: "DELETE",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
    }
  }
);
const data = await response.json();
GET /interview-invites List interview invites
JWT Required

List invites for the current organization. Optional filters narrow by lead, deal, template, or status.

Query Parameters

NameTypeRequiredDescription
lead_id integer Optional
deal_id integer Optional
template_id integer Optional
status string Optional Values: pending, started, submitted, expired

Response

List of invites

{
    "data": [
        {
            "id": 1,
            "organization_id": 1,
            "template_id": 1,
            "lead_id": 1,
            "deal_id": 1,
            "token": "...",
            "recipient_email": "...",
            "recipient_name": "...",
            "status": "pending",
            "expires_at": "2026-01-15T09:30:00.000000Z",
            "sent_at": "2026-01-15T09:30:00.000000Z",
            "submitted_at": "2026-01-15T09:30:00.000000Z",
            "created_by": 1,
            "created_at": "2026-01-15T09:30:00.000000Z"
        }
    ]
}

Code Examples

curl -X GET "https://crm.revorbit.com/api/interview-invites" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
const response = await fetch(
  "https://crm.revorbit.com/api/interview-invites",
  {
    method: "GET",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
    }
  }
);
const data = await response.json();
POST /interview-invites Create interview invite
JWT Required

Create a per-prospect invite with a 64-character random hex token. Optionally sends a branded email via Resend.

Request Body

NameTypeRequiredDescription
template_id integer Required
lead_id integer Optional Link the invite to an existing lead. If set, the form pre-fills name/email/company.. Nullable
deal_id integer Optional Link the invite to an existing deal. Mutually compatible with lead_id.. Nullable
recipient_email string Required
recipient_name string Optional
expires_at datetime Optional Nullable
send_email boolean Optional If true, deliver the invite email via Resend with the org's branding. Skipped on dev.
personal_note string Optional Optional rep-authored note prepended to the invite email body.. Nullable

Response

Invite created

{
    "id": 1,
    "organization_id": 1,
    "template_id": 1,
    "lead_id": 1,
    "deal_id": 1,
    "token": "...",
    "recipient_email": "...",
    "recipient_name": "...",
    "status": "pending",
    "expires_at": "2026-01-15T09:30:00.000000Z",
    "sent_at": "2026-01-15T09:30:00.000000Z",
    "submitted_at": "2026-01-15T09:30:00.000000Z",
    "created_by": 1,
    "created_at": "2026-01-15T09:30:00.000000Z"
}

Code Examples

curl -X POST "https://crm.revorbit.com/api/interview-invites" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": 1,
    "lead_id": 1,
    "deal_id": 1,
    "recipient_email": "...",
    "recipient_name": "...",
    "expires_at": "2026-01-15T09:30:00.000000Z",
    "send_email": true,
    "personal_note": "..."
}'
const response = await fetch(
  "https://crm.revorbit.com/api/interview-invites",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
      "Content-Type": "application/json"
    },
    body: JSON.stringify(
      {
          "template_id": 1,
          "lead_id": 1,
          "deal_id": 1,
          "recipient_email": "...",
          "recipient_name": "...",
          "expires_at": "2026-01-15T09:30:00.000000Z",
          "send_email": true,
          "personal_note": "..."
      }
    )
  }
);
const data = await response.json();
GET /interview-invites/{id} Get interview invite
JWT Required

Path Parameters

NameTypeRequiredDescription
id integer Required Resource ID

Response

Invite details

{
    "id": 1,
    "organization_id": 1,
    "template_id": 1,
    "lead_id": 1,
    "deal_id": 1,
    "token": "...",
    "recipient_email": "...",
    "recipient_name": "...",
    "status": "pending",
    "expires_at": "2026-01-15T09:30:00.000000Z",
    "sent_at": "2026-01-15T09:30:00.000000Z",
    "submitted_at": "2026-01-15T09:30:00.000000Z",
    "created_by": 1,
    "created_at": "2026-01-15T09:30:00.000000Z"
}

Code Examples

curl -X GET "https://crm.revorbit.com/api/interview-invites/{id}" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
const response = await fetch(
  "https://crm.revorbit.com/api/interview-invites/{id}",
  {
    method: "GET",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
    }
  }
);
const data = await response.json();
PUT /interview-invites/{id}/expire Expire interview invite
JWT Required

Mark an invite as expired so it can no longer be submitted.

Path Parameters

NameTypeRequiredDescription
id integer Required Resource ID

Code Examples

curl -X PUT "https://crm.revorbit.com/api/interview-invites/{id}/expire" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
const response = await fetch(
  "https://crm.revorbit.com/api/interview-invites/{id}/expire",
  {
    method: "PUT",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
    }
  }
);
const data = await response.json();
GET /interview-invites/{id}/responses Get interview responses
JWT Required

Fetch the submitted answers for an invite, including computed rep flags (e.g. competitive deal, fast timeline, high compliance).

Path Parameters

NameTypeRequiredDescription
id integer Required Resource ID

Response

Submitted answers and rep flags

{
    "invite_id": 1,
    "template_id": 1,
    "status": "started",
    "answers": {},
    "rep_flags": [
        "..."
    ],
    "submitted_at": "2026-01-15T09:30:00.000000Z"
}

Code Examples

curl -X GET "https://crm.revorbit.com/api/interview-invites/{id}/responses" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
const response = await fetch(
  "https://crm.revorbit.com/api/interview-invites/{id}/responses",
  {
    method: "GET",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
    }
  }
);
const data = await response.json();
POST /interview-invites/{id}/seed-configuration Seed product configuration from interview
JWT Required

Create a draft Product Configuration on the invite's deal by routing the prospect's `product_line` answer to a configurator definition (slug match) and applying the template's `field_map` rules to extract platform_keys, feature_keys, license_type, and quantity from the submitted answers. Returns the new configuration ID; the wizard can then be opened against it.

Path Parameters

NameTypeRequiredDescription
id integer Required Resource ID

Response

Draft configuration created

{
    "configuration_id": 1
}

Code Examples

curl -X POST "https://crm.revorbit.com/api/interview-invites/{id}/seed-configuration" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
const response = await fetch(
  "https://crm.revorbit.com/api/interview-invites/{id}/seed-configuration",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer YOUR_JWT_TOKEN",
    }
  }
);
const data = await response.json();

Public Interviews

GET /public/interview/{token} Load public interview form
Public

Return the template + any in-progress answers for the prospect's invite. The 64-character hex token in the URL is the only credential. For lead-capture mode (`/public/interview/capture/{slug}`), use the slug variant below. Rate-limited 100 requests / 10 minutes per IP.

Path Parameters

NameTypeRequiredDescription
token string Required

Code Examples

curl -X GET "https://crm.revorbit.com/api/public/interview/{token}"
const response = await fetch(
  "https://crm.revorbit.com/api/public/interview/{token}",
  {
    method: "GET",
    headers: {
    }
  }
);
const data = await response.json();
PATCH /public/interview/{token} Auto-save interview answers
Public

Persist a partial set of answers without submitting. Called on every change as the prospect fills out the form so they can leave and resume later. Rate-limited 100 requests / 10 minutes per IP.

Path Parameters

NameTypeRequiredDescription
token string Required

Request Body

NameTypeRequiredDescription
answers object Optional Map of question_key → answer value

Code Examples

curl -X PATCH "https://crm.revorbit.com/api/public/interview/{token}" \
  -H "Content-Type: application/json" \
  -d '{"answers":{}}'
const response = await fetch(
  "https://crm.revorbit.com/api/public/interview/{token}",
  {
    method: "PATCH",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(
      {
          "answers": {}
      }
    )
  }
);
const data = await response.json();
POST /public/interview/{token}/submit Submit interview
Public

Final submission of the interview. Marks the invite as `submitted`, locks answers from further edits, fires the `interview_submitted` notification to the assigned rep, and (for lead-capture mode) creates a Lead.

Path Parameters

NameTypeRequiredDescription
token string Required

Request Body

NameTypeRequiredDescription
answers object Optional Final answer set (also accepted via prior PATCH calls).

Code Examples

curl -X POST "https://crm.revorbit.com/api/public/interview/{token}/submit" \
  -H "Content-Type: application/json" \
  -d '{"answers":{}}'
const response = await fetch(
  "https://crm.revorbit.com/api/public/interview/{token}/submit",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(
      {
          "answers": {}
      }
    )
  }
);
const data = await response.json();
GET /public/interview/capture/{slug} Load lead-capture form
Public

Return the public lead-capture template by slug. Anyone can submit; on submit a new Lead is created. Optional `?r={user_id}` query param auto-assigns the captured Lead to that rep (validated against `organization_users.seat_active`). Rate-limited 100 requests / 10 minutes per IP.

Path Parameters

NameTypeRequiredDescription
slug string Required

Query Parameters

NameTypeRequiredDescription
r integer Optional Optional user_id to auto-assign the captured lead. Only honored if the user is an active seat in the template's organization.

Code Examples

curl -X GET "https://crm.revorbit.com/api/public/interview/capture/{slug}"
const response = await fetch(
  "https://crm.revorbit.com/api/public/interview/capture/{slug}",
  {
    method: "GET",
    headers: {
    }
  }
);
const data = await response.json();
POST /public/interview/capture/{slug}/submit Submit lead-capture interview
Public

Create a new Lead from the submitted answers and (if `?r={user_id}` was set on the show endpoint) assign it to that rep. Fires the `lead_captured` notification.

Path Parameters

NameTypeRequiredDescription
slug string Required

Query Parameters

NameTypeRequiredDescription
r integer Optional Optional user_id to auto-assign the new Lead. Validated against organization_users.seat_active.

Request Body

NameTypeRequiredDescription
answers object Optional

Code Examples

curl -X POST "https://crm.revorbit.com/api/public/interview/capture/{slug}/submit" \
  -H "Content-Type: application/json" \
  -d '{"answers":{}}'
const response = await fetch(
  "https://crm.revorbit.com/api/public/interview/capture/{slug}/submit",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(
      {
          "answers": {}
      }
    )
  }
);
const data = await response.json();