Sparky AI Reports — Integration Guide

Use the LiveSwitch API to run, view, and manage Sparks from a third-party system. Sparks are AI reports under the Sparky brand. Developers can follow this guide manually or give it to an AI agent for implementation.

To use this guide with an AI agent:

  1. Add this whole file to the agent's context.
  2. Add your LiveSwitch API credentials (client ID and redirect URI).
  3. Specify the scenarios from Section 4 that the agent must implement.

Section 6 gives the agent a complete endpoint reference without the need to read the earlier sections again.


1. What This Feature Does

Sparks are AI reports and analyses under the "Sparky" brand. LiveSwitch can run them on these API entities:

  • A Conversation: The product UI calls this a Session. It is one interaction, such as a live call, recording request, photo session, or upload.
  • A Project: A container for multiple Conversations, such as a job, claim, or installation. A Project report can summarize all content in the Project.
TermMeaning
ConversationOne session or interaction. A Conversation has a lifecycle (status). It holds recordings, photos, and documents.
ProjectA group of Conversations with contacts, tags, and attributes. A Project has its own status (NotStarted, InProgress, Completed).
Spark templateThe definition of a report type. It specifies what the report analyzes. It specifies the inputs, if any. The API provides Spark templates. You cannot create Spark templates yourself.
Spark runOne execution of a Spark template on a Conversation or Project. Its lifecycle is queued → running → completed | failed | cancelled.
Task / InputA Spark template can define one or more tasks. Each task has typed input fields for the start of a Spark run, such as free-text instructions or a required document. Some inputs use valid answers from a connected platform, such as a customer in SmartMoving.
Validation tokenThe result of POST /v1/spark-templates/{id}/validate-inputs. It holds the validated inputs. A Spark run uses it when the Spark template has user inputs.

2. Prerequisites & Authentication

2.1 Authentication

Sparks use the same authentication as the rest of the API. Follow the Authentication page. It gives the base URL of the API. It also explains how to:

  • Get a Developer App (client_id and client_secret).
  • Log in a user and get an access token.
  • Refresh the access token.

Send the access token in the Authorization: Bearer {access_token} header on every request.

For Sparks, add the scopes in section 2.2 to the scope value of the login URL.

2.2 Required scopes

ScopeGrants
openid profile emailRequired for every integration, regardless of the endpoints
sparksRead Spark runs (list or get)
sparks.writeCreate and delete Spark runs, and validate Spark inputs
spark-templatesList Spark templates and get the options for their inputs
conversations / conversations.writeRead, create, and update Conversations (sessions)
projects / projects.writeRead, create, and update Projects
webhooks / webhooks.writeView and manage webhook subscriptions for the "run when data arrives" scenario. Only administrators have access. Regular users get 403 on all webhook endpoints, which includes read requests.

3. Core Concepts You Need Before Writing Code

3.1 Spark run lifecycle — there is no manual "start"

When you POST a Spark run, LiveSwitch immediately creates it with queued status.
The API returns 202 Accepted.
This occurs even if the recording or other media is not ready.
LiveSwitch automatically changes the status to running when the media becomes available.
The final status is completed, failed, or cancelled.

queued → running → completed | failed | cancelled

For the scenario in §4.4, you can request a Spark run at any time.
You do not need to schedule the Spark run.
LiveSwitch waits until the media is available before it starts the Spark run.

3.2 Conversation status — your "is there data yet?" signal

ConversationDto.status is a plain string.
This value is relevant to Spark runs:

ReadyForReview means that at least one recording is available for this Conversation.

A Conversation has several other status values during its lifecycle:

StatusMeaning
NotStartedThe Conversation exists but has no activity yet
SentLiveSwitch sent an invitation or notification to the contact
ScheduledA Scheduled-type Conversation awaits its startAt time
InProgressThe session is active
ReadyForReviewAt least one recording is available. This status is the trigger for Spark runs.
ReviewedSomeone reviewed the Conversation in the LiveSwitch app

Use webhooks to monitor this status.
Do not poll for it.
If a Conversation gets multiple recordings, ReadyForReview can occur more than once.
Do not treat this status as a single final event.

3.3 No native "report ready" event (yet)

LiveSwitch has no "Spark completed" or "Conversation ended" webhook event.
It supports generic Create / Update / Delete events for a fixed set of entities:

  • Conversations (Conversations)
  • Contacts (Contacts)
  • App installations (AppInstallations)
  • Recordings (Recordings)
  • Documents (Documents)
  • Accounts (Accounts)

Poll GET /v1/sparks/{id} or the list endpoints to find out when a report finishes.
LiveSwitch plans a dedicated "Spark completed" event for a future release.
This guide will change when that event becomes available.


4. Scenario Walkthroughs

4.1 Discover available report types (Spark templates)

Before you start a Spark run, get your organization's available Spark templates and their inputs:

GET /v1/spark-templates?installed=true&limit=50
Authorization: Bearer {token}

The response uses SparkTemplatesResponseDto:

{
  "data": [
    {
      "id": "template-uuid",
      "name": "Damage Assessment Summary",
      "description": "Summarizes visible damage from session photos/recordings.",
      "category": { "id": "cat-uuid", "name": "Field Service", "description": "..." },
      "requiresUserInput": true,
      "requiresPlatformLogin": false,
      "tasks": [
        {
          "id": "task-1",
          "codeName": "summary-task",
          "name": "Summary",
          "type": "user-input",
          "inputs": [
            {
              "key": "focusArea",
              "label": "Focus Area",
              "type": "text",
              "required": false,
              "description": "...",
              "multiple": false,
              "options": null,
              "lookup": null,
              "validation": { "required": false, "minLength": null, "maxLength": 200, "min": null, "max": null, "pattern": null, "patternMessage": null },
              "default": null
            }
          ],
          "isRequired": true
        }
      ],
      "createdAt": "...",
      "updatedAt": "..."
    }
  ],
  "nextCursor": "opaque-cursor-string-or-null"
}

To get the next page, send nextCursor as cursor.
Repeat until nextCursor is null.
Record the id for sparkTemplateId.
Record each task's codeName and input keys for §4.2/4.3.

Each input specifies how to get a valid answer:

FieldMeaning
typeThe value type: text, textarea, number, email, phone, url, date, datetime, time, checkbox, select, radio, multiselect, autocomplete or multi_autocomplete.
requiredIf true, the input requires a value.
multipleIf true, the input accepts a list of answers.
optionsA fixed list of valid answers. The input accepts only the value of an option.
lookupThe answers come from a connected platform. The options endpoint provides them (§4.2, step 1).
validationThe limits for the answer. The minLength, maxLength and pattern limits apply to text.
defaultThe value that the Spark run uses if you do not send this input.

An input cannot define both options and lookup.
This SmartMoving example shows an input with lookup:

{
  "key": "quote_number",
  "label": "Quote Number",
  "type": "select",
  "required": true,
  "multiple": false,
  "options": null,
  "lookup": {
    "hasOptions": true,
    "searchable": false,
    "displayLabelRequired": false,
    "platformName": "SmartMoving",
    "dependsOn": ["customer_name"]
  }
}
lookup fieldMeaning
hasOptionsIf true, the options endpoint provides the valid answers.
searchableIf true, the options endpoint requires a search term, such as a name, phone number, or email.
dependsOnThe keys of inputs in the same task that require answers first. In this example, a customer selection is necessary before you can get the quotes.
displayLabelRequiredIf true, the platform uses the option label to confirm the value. The input requires the label with the value.
platformNameThe platform that provides the answers.

4.2 Start a Spark run on an existing Conversation (session)

If the Spark template has no user inputs (requiresUserInput: false), send only the Spark template ID:

POST /v1/conversations/{conversationId}/sparks
Authorization: Bearer {token}
Content-Type: application/json

{
  "sparkTemplateId": "template-uuid",
  "shareWith": ["anyone"]
}

If the Spark template has user inputs (requiresUserInput: true), complete these three steps:

  1. Get the valid options for each selection input.
  2. Validate all the inputs to get a validation token (validationToken).
  3. Start the Spark run with the validation token (validationToken).

The examples use the SmartMoving Spark template "Create a Moving Inventory in SmartMoving".
Its task identify_opportunity_id has two inputs:

  • Customer lookup (customer_name): A searchable lookup
  • Quote lookup (quote_number): A lookup that depends on customer_name

Step 1 — Get the options for each selection input

Repeat this step for each input with lookup or options.
For a free-text input, go to step 2.

GET /v1/spark-templates/{sparkTemplateId}/tasks/{taskCodeName}/inputs/{fieldKey}/options
Authorization: Bearer {token}
Query parameterWhen to send it
searchIf lookup.searchable is true, send search. The search term must have 3 or more characters.
parent[key]For each key in lookup.dependsOn, send this parameter. Use the value of the option selected for that input.

Find the customer:

GET /v1/spark-templates/{sparkTemplateId}/tasks/identify_opportunity_id/inputs/customer_name/options?search=Peter
{
  "options": [
    { "value": "086d9a35-f81d-413d-8188-b3e000bf0775", "label": "Peter Arroyo", "search": "Peter" }
  ]
}

Get the quotes for the selected customer:

GET /v1/spark-templates/{sparkTemplateId}/tasks/identify_opportunity_id/inputs/quote_number/options?parent[customer_name]=086d9a35-f81d-413d-8188-b3e000bf0775
{
  "options": [
    { "value": "a9491534-767e-46c1-a7d7-b4d400cfab1f", "label": "Quote Number 2259" },
    { "value": "b532ec0a-49eb-4119-b45e-b4d5004fca25", "label": "Quote Number 2263" }
  ]
}

Select an option in your code or show these options to your user.
Keep the full option object for step 2.

Step 2 — Validate the inputs

Send the inputs for all tasks.
For a lookup input, send the option object exactly as step 1 returned it (value, label and search).
Do not send only the label.
The API cannot find "Peter Arroyo" as a value.

POST /v1/spark-templates/{sparkTemplateId}/validate-inputs
Authorization: Bearer {token}
Content-Type: application/json

{
  "tasks": [
    {
      "codeName": "identify_opportunity_id",
      "inputs": {
        "customer_name": { "value": "086d9a35-f81d-413d-8188-b3e000bf0775", "label": "Peter Arroyo", "search": "Peter" },
        "quote_number": { "value": "a9491534-767e-46c1-a7d7-b4d400cfab1f", "label": "Quote Number 2259" }
      }
    }
  ]
}

Use these value formats:

  • Text, number, date: Send the value. Send date and datetime in ISO 8601 format (2026-10-01, 2026-10-01T14:30:00Z).
  • Checkbox (checkbox): Send true or false.
  • Fixed list (options): Send only the value of the option.
  • Lookup (lookup): Send the option object from step 1.
  • Multiple values (multiple: true): Send a list of values or option objects.

For fixed-list inputs, the API adds the label.
For lookup inputs, the API also accepts displayLabel instead of label.
The API searches the connected platform again to confirm each lookup value.
If the inputs are valid, the API returns 200:

{
  "valid": true,
  "validationToken": "eyJ...",
  "validatedAt": "2026-10-18T15:10:19Z",
  "expiresAt": "2026-10-19T15:10:19Z"
}

If an input is invalid, the API returns 422.
The response groups errors by task and input key:

{
  "title": "ValidationFailed",
  "status": 422,
  "detail": "Spark validation failed. See errors for the affected tasks and required platform connections.",
  "errors": {
    "tasks": [
      {
        "codeName": "identify_opportunity_id",
        "inputs": {
          "customer_name": [
            "No matching option found for 'Customer Name' with value 'Peter'",
            "'Customer Name' is looked up in SmartMoving. Find it with GET /v1/spark-templates/.../options?search=..., then send back the option you picked exactly as returned, including its search: { \"value\": ..., \"label\": ..., \"search\": ... }."
          ]
        }
      }
    ]
  }
}
ErrorCause
Field '…' is requiredA required input has no value.
No matching option found for '…' with value '…'The platform does not have this value. Or the value does not belong to the selected parent, such as a quote for a different customer.
Unknown input field.The task does not have this input key.
Unknown task code names: …The Spark template does not have this task codeName.

Step 3 — Start the Spark run with the validation token

POST /v1/conversations/{conversationId}/sparks
Authorization: Bearer {token}
Content-Type: application/json

{
  "sparkTemplateId": "template-uuid",
  "validationToken": "eyJ...",
  "shareWith": ["anyone"]
}

The validation token has these properties:

  • The validation token holds the validated inputs
  • The validation token is valid for 24 hours
  • The validation token becomes invalid earlier if the Spark template changes
  • A valid validation token can be part of more than one create call
  • Each create call starts a new Spark run with the same Spark template and inputs
  • The validation token is specific to one Spark template

The API returns these errors:

  • With both tasks and a validation token, the API returns 400
  • With an invalid validation token, the API returns 422 The validation token is not valid. Validate the inputs again.
  • With a validation token for a different Spark template, the API returns 422
  • Without a validation token for a Spark template with user inputs, the API returns 422 Validate the inputs first …

Do not send tasks with the validation token.

Run without validation. A request with tasks, "skipInputValidation": true, and no validation token bypasses input validation. The API does not examine the inputs. An incorrect input can cause a Spark run to use incorrect data. This option is for inputs that are already correct.

The shareWith: ["anyone"] field makes the completed report public through a shareUrl (see §4.5).
To keep the report private to your organization, omit this field.

The response is 202 Accepted:

{ "id": "spark-run-uuid", "status": "queued" }

Poll GET /v1/sparks/{id} until status is completed/failed/cancelled.

4.3 Start a Spark run on an existing Project

The Project endpoint accepts the same request format as the Conversation endpoint.
A Project report summarizes all content in the Project.

POST /v1/projects/{projectId}/sparks
Authorization: Bearer {token}
Content-Type: application/json

{
  "sparkTemplateId": "template-uuid",
  "validationToken": "eyJ...",
  "shareWith": ["anyone"]
}

If the Spark template has user inputs, complete steps 1 and 2 of §4.2 first.
A validation token works for both Conversations and Projects.
The response has the same { "id": ..., "status": "queued" } format.
Poll for the status as in §4.2.

4.4 Automatically run a report as soon as session data comes in

Select the procedure that matches the report trigger:

A. You know the Conversation ID and need the report as soon as its recording arrives.

Call the POST endpoint in §4.2 immediately.
For example, call it after you create the Conversation or when a user requests a report.
No additional automation is necessary.
Spark runs start with queued status.
They automatically change to running only when media exists.
You can send the request before the recording finishes.

B. You need reports for Conversations that you do not directly control.

Examples include each new session in a Project or each new recording for an existing Conversation.
Use webhooks for these cases.

Step 1 — Create a webhook subscription

Create a webhook subscription:

POST /v1/webhooks
Authorization: Bearer {token}
Content-Type: application/json

{
  "eventType": "Update",
  "entityName": "Conversations",
  "name": "Auto-run Sparky report",
  "url": "https://your-system.example.com/webhooks/liveswitch",
  "enabled": true
}

To receive events for new sessions too, also subscribe to eventType: "Create" on Conversations.

Step 2 — Handle webhook deliveries

Handle webhook deliveries.
Each callback includes these headers:

HeaderMeaning
x-liveswitch-transaction-idUnique delivery ID
x-liveswitch-entity-idThe Conversation ID
x-liveswitch-webhook-idThe subscription that triggered the callback
x-liveswitch-webhook-event-typeCREATE / UPDATE / DELETE
x-liveswitch-webhook-entity-nameconversation

Webhook payloads contain the entity DTO (ConversationDto for Conversation events).
Some events contain incomplete entity details.
If the body lacks status or other required fields, get the current state with GET /v1/conversations/{x-liveswitch-entity-id}.

Step 3 — Request the Spark run

Check for the "ready" status.
If the Conversation is ready, request the Spark run:

def on_webhook(headers, body):
    conversation = body if "status" in body else get_conversation(headers["x-liveswitch-entity-id"])
    if conversation["status"] == "ReadyForReview":
        if not already_sparked(conversation["id"]):   # status can repeat — dedupe yourself
            create_spark_for_conversation(conversation["id"], template_id="...")

Prevent duplicate Spark runs in your system.
For example, check whether a Spark run already exists for the same Conversation and recording.
The ReadyForReview event can occur again when the Conversation gets a second recording.

For Spark templates with user inputs, create_spark_for_conversation must validate the inputs (§4.2, step 2).
It must send the new validation token (validationToken).
When the webhook arrives, validate the inputs.
When you subscribe, do not validate the inputs.
A validation token is valid for only 24 hours.

Step 4 — Respond to the webhook

Respond quickly with 2xx.
After a 5xx response, LiveSwitch retries the delivery up to 3 times.
LiveSwitch does not retry after a 4xx response.

Webhook deliveries do not currently have signatures.
To validate a delivery, check that x-liveswitch-webhook-id matches a subscription that you created.
Consider a private or secret URL path for your endpoint.

4.5 Pull existing reports (view reports)

List all Spark runs on a Conversation:

GET /v1/conversations/{conversationId}/sparks

List all Spark runs on a Project:

GET /v1/projects/{projectId}/sparks

Both endpoints return this format:

{
  "data": [
    { "id": "...", "sparkTemplateId": "...", "status": "completed", "createdAt": "...", "shareUrl": "https://..." }
  ],
  "total": 3
}

Get one Spark run to poll its status or get its share link:

GET /v1/sparks/{id}

This endpoint returns the same fields as one data[] entry above.
Neither list endpoint currently supports pagination.
Typical Conversations and Projects have too few Spark runs for this limit to cause a problem.
This limit can matter when a Conversation or Project has many Spark runs.

SparkDto exposes only metadata (id, sparkTemplateId, status, createdAt, shareUrl).
It does not expose report content directly.
Users can edit reports in the LiveSwitch app UI.
A report copy from the API can become outdated as soon as a user edits the report.
A report link always opens the current version.

The shareUrl field has a value if you sent shareWith: ["anyone"] at creation.
This URL is public.
It requires no login.
The LiveSwitch app UI also shows completed Spark runs in the Conversation or Project.

To view a completed report, select one method:

  • Use the shareUrl.
  • Open the Conversation or Project in the LiveSwitch app UI through conversationUrl / projectUrl.

If your integration needs report content in its own UI, provide a link to shareUrl.
A link guarantees access to the latest edited version.
A copy of the content cannot give this guarantee.

4.6 "Updating" a report

The API has no PUT/PATCH endpoint for Spark runs.
Users edit report content in the LiveSwitch app UI.
The API supports only Create (POST) and Delete (DELETE) operations for Spark runs.

To change a report's inputs and generate it again:

  1. Use DELETE to delete the old Spark run.
  2. Validate the new inputs (§4.2, step 2).
  3. Use POST to create a new Spark run with the new validation token (validationToken).

4.7 Delete a report

DELETE /v1/sparks/{id}

When you delete a Spark run, LiveSwitch also cancels any schedule that awaits execution or is in the queue.
LiveSwitch also removes the analysis job.
You can safely delete a Spark run with queued or running status to cancel it.
Deletion also works for completed Spark runs.


5. End-to-End Example: Full Automation Flow

A typical integration automatically creates reports for new field-service sessions.
Your system or a LiveSwitch app user creates a Conversation.
Your system uses POST /v1/conversations for this step.
The Conversation can optionally link to a Project through projectId/projectExternalId.
After a recording arrives, status becomes ReadyForReview.
The webhook subscription from §4.4 receives an Update event.

Then complete these steps:

  1. Check for an existing Spark run to prevent duplicate Spark runs for the same Conversation.
  2. If the Spark template has user inputs, get the options (§4.2, step 1).
  3. If the Spark template has user inputs, validate the inputs (§4.2, step 2).
  4. Call POST /v1/conversations/{id}/sparks with the appropriate sparkTemplateId.
    If the Spark template has user inputs, include the validation token (validationToken).
  5. Poll GET /v1/sparks/{id} until status is completed.
    For example, poll every 30–60 seconds or use a job queue.
  6. If you enabled report sharing, get the shareUrl.
    Store or forward the URL.
    Alternatively, direct users to the Conversation's conversationUrl in the LiveSwitch app.
  7. If you no longer need the report, delete it with DELETE /v1/sparks/{id}.

6. API Quick Reference

ActionMethod & PathScopeNotes
List Spark templatesGET /v1/spark-templatesspark-templatesQuery: installed, limit, cursor
Get the options for a Spark template inputGET /v1/spark-templates/{sparkTemplateId}/tasks/{taskCodeName}/inputs/{fieldKey}/optionsspark-templatesQuery: search (3 or more characters when lookup.searchable is true), parent[key] (for each key in lookup.dependsOn)
Validate Spark template inputsPOST /v1/spark-templates/{sparkTemplateId}/validate-inputssparks.writeBody: tasks[]. Returns a validation token in validationToken (valid for 24 hours)
List Spark runs on a ConversationGET /v1/conversations/{conversationId}/sparkssparksReturns {data[], total}
Start a Spark run on a ConversationPOST /v1/conversations/{conversationId}/sparkssparks.writeBody: sparkTemplateId, validationToken (for Spark templates with user inputs), shareWith[]. Alternative: tasks[] with skipInputValidation: true
List Spark runs on a ProjectGET /v1/projects/{projectId}/sparkssparksReturns {data[], total}
Start a Spark run on a ProjectPOST /v1/projects/{projectId}/sparkssparks.writeSame body format as the Conversation request
Get one Spark runGET /v1/sparks/{id}sparksPoll for status
Delete a Spark runDELETE /v1/sparks/{id}sparks.writeAlso cancels Spark runs with queued or running status
Get a ConversationGET /v1/conversations/{id}conversationsCheck status
List ConversationsGET /v1/conversationsconversationspage, pageSize, where, order
Create a ConversationPOST /v1/conversationsconversations.writeThe request requires type. The Conversations API reference gives the full request body.
Update a ConversationPUT /v1/conversations/{id}conversations.writeOnly contactId, notes, tags, name, projectId, assignedUserId are editable
Get a ProjectGET /v1/projects/{id}projects
List ProjectsGET /v1/projectsprojectspage, pageSize, where, order, status, externalId, contactId
Create a ProjectPOST /v1/projectsprojects.writeThe request requires name
Update a ProjectPUT /v1/projects/{id}projects.write
Create webhook subscriptionPOST /v1/webhookswebhooks.writeThe request requires eventType + entityName
List webhooksGET /v1/webhookswebhooks
Get a webhookGET /v1/webhooks/{id}webhooks
Update a webhookPUT /v1/webhooks/{id}webhooks.write
Delete a webhookDELETE /v1/webhooks/{id}webhooks.write
Delete all webhooks for an appDELETE /v1/webhooks/app/{appId}webhooks.write

Did this page help you?