Getting started

Quickstart - IECC Direct API Call Integration Guide

Use the Evergrove agent API directly to create scheduler entities, schedule outbound calls, trigger them, and poll for outcomes when building an IECC integration.

Prerequisites

Before you start, obtain an API key from Evergrove Labs. You can set key rotation to quarterly, yearly, or another agreed cadence.

Base URL and authentication

Send every request to https://agent-api.evergrovelabs.com. Trim any trailing slash from the base URL before appending paths in application code.

Every JSON request must include these headers:

Authorization: Bearer {API_KEY}
Accept: application/json
Content-Type: application/json

In curl examples and generated client code, define the following variables:

export API_URL="https://agent-api.evergrovelabs.com"
export API_KEY="<provided key>"

Endpoints

Endpoint

Method

Purpose

${API_URL}/scheduler/entities

POST

Create or update one callable scheduler entity.

${API_URL}/scheduler/requests

POST

Create queued scheduled requests.

${API_URL}/scheduler/trigger/v2

POST

Start one queued scheduled request.

${API_URL}/scheduler/requests/{requestId}

GET

Poll request status and outcomes.

Shared schemas

Normalized call row

Prepare one normalized row per outbound call before using the API:

interface NormalizedCallRow {
  external_reference_id: string;
  organization_name: string;
  patient_name: string;
  patient_ssn?: string | null;
  patient_dob: string;                 // YYYY-MM-DD
  patient_phone_number?: string | null; // optional NANP phone; API normalizes to E.164
  date_of_injury: string;                // YYYY-MM-DD
  expected_appointment_date_time: string; // YYYY-MM-DDTHH:mm:ss
  local_timezone: string;                // e.g. America/New_York
  service_modality: string;
  claim_number: string;
  insurer_group_name: string;
  body_part: string;
  provider_office: string;
  provider_office_address: string;
  provider_state?: string | null;
  outbound_phone_number: string;         // callable NANP E.164 provider phone
  eoc_number: string;
  notes?: string | null;
}

Recommended validation rules:

  • external_reference_id must be stable and unique per source row.

  • outbound_phone_number is required and must be a callable NANP E.164 number, for example +12125550199.

  • patient_phone_number is optional; omit it, send null, or send NONE when blank. The API accepts valid NANP input and normalizes it to +1....

  • patient_ssn is optional; omit it, send null, send NONE, send 9 digits, or send last 4 digits.

  • patient_dob and date_of_injury must be ISO dates in YYYY-MM-DD format.

  • expected_appointment_date_time must be a timezone-naive ISO datetime. Do not include Z, offsets, dates without times, or fractional seconds.

  • local_timezone must be a canonical region IANA timezone, for example America/New_York.

  • provider_state is optional and may be a valid US state abbreviation or full state name.

  • Use claim_number: "Not Available" if no claim number exists.

  • organization_name must be enabled for the tenant associated with the provided API key; otherwise scheduling returns 422.

Working hours policy

interface WorkingHoursWindow {
  start: string; // HH:mm
  end: string;   // HH:mm
}

interface WorkingHoursDayPolicy {
  default_call_time?: string | null; // HH:mm
  windows?: WorkingHoursWindow[];
}

interface WorkingHoursPolicy {
  monday?: WorkingHoursDayPolicy;
  tuesday?: WorkingHoursDayPolicy;
  wednesday?: WorkingHoursDayPolicy;
  thursday?: WorkingHoursDayPolicy;
  friday?: WorkingHoursDayPolicy;
  saturday?: WorkingHoursDayPolicy;
  sunday?: WorkingHoursDayPolicy;
}

Working-hours objects reject extra fields. A day with windows must include default_call_time, and that default must fall inside one of the windows. A day with no windows is closed and must not set default_call_time.

Default policy used by the existing flow:

{
  "monday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
  "tuesday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
  "wednesday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
  "thursday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
  "friday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
  "saturday": {},
  "sunday": {}
}

Step 1: Create scheduler entity

POST /scheduler/entities upserts by name within the authenticated tenant. If an entity with the same name exists, the endpoint updates its schedule and location fields and returns the existing entity. Persist the returned id as entity_id for the row.

Request schema

interface CreateSchedulerEntityRequest {
  name: string;
  location_name?: string | null;
  location_timezone: string; // IANA timezone, e.g. America/New_York
  working_hours_policy: WorkingHoursPolicy;
  ivr_answer_key_guide?: string | null;
}

Request field

Source

name

NormalizedCallRow.provider_office

location_name

NormalizedCallRow.provider_office

location_timezone

NormalizedCallRow.local_timezone

working_hours_policy

Caller-defined calling window; default Monday–Friday 09:00–17:00

ivr_answer_key_guide

Optional IVR instructions for the agent.

Example request

curl -X POST "$API_URL/scheduler/entities" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Select Physical Therapy",
    "location_name": "Select Physical Therapy",
    "location_timezone": "America/New_York",
    "working_hours_policy": {
      "monday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
      "tuesday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
      "wednesday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
      "thursday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
      "friday": { "default_call_time": "09:00", "windows": [{ "start": "09:00", "end": "17:00" }] },
      "saturday": {},
      "sunday": {}
    }
  }'

Response schema

interface SchedulerEntity {
  id: string;
  tenant_id: string;
  name: string;
  location_name: string | null;
  location_timezone: string;
  can_call: boolean;
  ivr_answer_key_guide?: string | null;
  working_hours_policy: WorkingHoursPolicy;
  working_hours_source?: string | null;
  working_hours_updated_at?: string | null;
  created_at: string;
}

Persist the mapping:

entityIdByExternalReference[row.external_reference_id] = entity.id;

Step 2: Schedule requests

After each call row has an entity_id, create queued scheduled requests. This step does not start calls.

Request schema

interface ScheduleRequestsRequest {
  calls: ScheduleRequestCallInput[];
}

type CallObjective = 'CONFIRM_IE_ATTENDANCE' | 'RESCHEDULE';

interface ScheduleRequestCallInput {
  entity_id: string;            // UUID
  external_reference_id?: string; // if you create scheduled request in bulk, this is how you can keep track of it
  outbound_phone_number: string;  // callable NANP E.164 provider phone
  objective: CallObjective;
  notes?: string | null;
  best_to_make_call_by?: string | null; // ISO datetime
  details: ScheduleRequestDetails;
}

interface ScheduleRequestDetails {
  organization_name: string;
  patient_name: string;
  patient_ssn?: string | null;
  patient_dob: string; // YYYY-MM-DD
  patient_phone_number?: string | null; // optional NANP phone; API normalizes to E.164
  date_of_injury: string; // YYYY-MM-DD
  expected_appointment_date_time: string; // YYYY-MM-DDTHH:mm:ss
  local_timezone: string;
  service_modality: string;
  claim_number?: string; // defaults to "Not Available" when blank or omitted
  insurer_group_name: string;
  body_part: string;
  provider_office: string;
  provider_office_address: string;
  provider_state?: string | null;
  eoc_number: string;
  notes?: string | null;
}

Use objective: "CONFIRM_IE_ATTENDANCE" for IECC attendance-confirmation calls. If any call in the request has external_reference_id, every call in that request must have one.

Field notes:

  • Omit details.patient_phone_number when unavailable.

  • Omit details.patient_ssn, set it to null, or send NONE when unavailable.

  • Put caller-facing notes in the top-level notes field. details.notes is accepted by the request model but is not part of the persisted initial-eval contract metadata.

Example request

curl -X POST "$API_URL/scheduler/requests" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "calls": [
      {
        "entity_id": "11111111-1111-4111-8111-111111111111",
        "external_reference_id": "row-0001",
        "outbound_phone_number": "+12125550199",
        "objective": "CONFIRM_IE_ATTENDANCE",
        "details": {
          "organization_name": "SPNet",
          "patient_name": "Jane Patient",
          "patient_ssn": "999-88-7777",
          "patient_dob": "1967-04-13",
          "patient_phone_number": "+12125550100",
          "date_of_injury": "2026-01-15",
          "expected_appointment_date_time": "2026-04-09T11:00:00",
          "local_timezone": "America/New_York",
          "service_modality": "physical therapy",
          "claim_number": "CLAIM-1",
          "insurer_group_name": "Acme Insurer Group",
          "body_part": "left shoulder",
          "provider_office": "Select Physical Therapy",
          "provider_office_address": "456 Provider Rd, New York, NY 10002",
          "provider_state": "NY",
          "eoc_number": "EOC-1"
        }
      }
    ]
  }'

Response schema

interface ScheduleRequestsResponse {
  scheduled_requests: ScheduledRequest[];
}

interface ScheduledRequest {
  id: string;                    // UUID
  call_input_id: string;         // UUID
  entity_id: string;             // UUID
  external_reference_id?: string | null;
  tenant_id: string;
  workflow_status: OutboundCallStatus;
  best_to_callback_after: string | null; // datetime or null
  generated_outcomes?: GeneratedOutcomes | null;
  created_at: string;
  updated_at: string;
}

type OutboundCallStatus =
  | 'ENQUEUED'
  | 'ACTIVE'
  | 'COMPLETE'
  | 'ERROR'
  | 'CANCELLED'
  | 'DO_NOT_CALL_BACK';

Map scheduled request IDs back to source rows:

const requestIdByExternalReference = Object.fromEntries(
  response.scheduled_requests.flatMap((request) =>
    request.external_reference_id
      ? [[request.external_reference_id, request.id]]
      : []
  )
);

Fail or retry if any expected external reference is missing:

const missing = rows.filter((row) => !requestIdByExternalReference[row.external_reference_id]);
if (missing.length) throw new Error('Missing scheduled request IDs');

Step 3: Trigger calls

Trigger a scheduled request ID to start the queued call workflow.

Request schema

interface TriggerRequestsRequest {
  scheduled_request_ids: [string]; // exactly one scheduled request UUID
  latency_mode?: 'low' | 'high';   // defaults to low
}

latency_mode defaults to low. Use low for a conversation experience; use high only when explicitly needed.

Example request

Low latency (default):

curl -X POST "$API_URL/scheduler/trigger/v2" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "scheduled_request_ids": ["22222222-2222-4222-8222-222222222222"],
    "latency_mode": "low"
  }'

High latency:

curl -X POST "$API_URL/scheduler/trigger/v2" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "scheduled_request_ids": ["22222222-2222-4222-8222-222222222222"],
    "latency_mode": "high"
  }'

Response schema

interface TriggerRequestsResponse {
  triggered: string[];
  workflow_id?: string;
  latency_mode?: 'low' | 'high';
  errors?: string[];
  message?: string;
}

Persist which request ID was triggered. If triggering multiple scheduled requests, call this endpoint once per scheduled request ID.

Step 4: Poll status and outcomes

Poll by scheduled request ID until the request reaches a terminal status. The default response is slim and focuses on request status plus generated_outcomes. Detailed attempt history is omitted unless explicitly requested.

Request schema

This endpoint has no JSON request body.

interface PollScheduledRequestPathParams {
  requestId: string;
}

interface PollScheduledRequestQueryParams {
  include_call_attempts?: boolean; // defaults to false
}

Example request

REQUEST_ID="22222222-2222-4222-8222-222222222222"

curl -X GET "$API_URL/scheduler/requests/$REQUEST_ID" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: application/json"

Include call attempts only when debugging or auditing a request:

curl -X GET "$API_URL/scheduler/requests/$REQUEST_ID?include_call_attempts=true" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: application/json"

Response schema

interface ScheduledRequestStatus {
  id: string; // UUID
  workflow_status: OutboundCallStatus;
  best_to_callback_after: string | null; // datetime or null
  generated_outcomes: GeneratedOutcomes | null;
  call_attempts?: CallAttempt[]; // present only when include_call_attempts=true
  created_at: string;
  updated_at: string;
}

interface CallAttempt {
  id: string; // UUID
  scheduled_request_id: string; // UUID
  tenant_id: string;
  attempt_number: number;
  status: 'PLACED' | 'ANSWERED' | 'FAILED' | 'COMPLETE' | 'LEGACY_COMPLETED';
  disposition?: 'ANSWERED' | 'RETRYABLE_ERROR' | 'NON_RETRYABLE_ERROR' | null;
  error_detail?: string | null;
  room_name?: string | null;
  workflow_id?: string | null;
  call_reference_time_utc?: string | null;
  transcript_bucket?: string | null;
  transcript_object_key?: string | null;
  generated_outcomes?: Record | null;
  agent_behavior_evaluation?: Record | null;
  recording_id?: string | null;
  created_at: string;
  updated_at: string;
}

interface GeneratedOutcomes {
  called: boolean;
  time_of_call?: string | null;
  voicemail_left?: boolean | null;
  person_spoke_with?: string | null;
  positive_or_negative_contact: 'positive' | 'negative' | 'unknown';
  original_appointment?: { date: string; time: string | null } | null;
  rescheduled_appointment?: { date: string; time: string | null } | null;
  additional_dates_of_service: Array;
  appointment_attendance_status:
    | 'attended'
    | 'canceled'
    | 'canceled_rescheduled'
    | 'no_show'
    | 'no_show_rescheduled'
    | 'unable_to_confirm'
    | 'unknown';
  reason_why?: string | null;
  bill_sending_confirmation: 'confirmed' | 'not_confirmed' | 'not_discussed';
  report_sending_confirmation: 'confirmed' | 'not_confirmed' | 'not_discussed';
}

Before completion, generated_outcomes is usually null. Once transcript processing finishes, generated_outcomes contains the best representative outcome selected across attempts. The call_attempts array is hidden by default and is returned only with include_call_attempts=true.

Example responses

Default active poll response:

{
  "id": "22222222-2222-4222-8222-222222222222",
  "workflow_status": "ACTIVE",
  "best_to_callback_after": null,
  "generated_outcomes": null,
  "created_at": "2026-04-09T14:59:30Z",
  "updated_at": "2026-04-09T15:00:05Z"
}

Default completed poll response:

{
  "id": "22222222-2222-4222-8222-222222222222",
  "workflow_status": "COMPLETE",
  "best_to_callback_after": null,
  "generated_outcomes": {
    "called": true,
    "time_of_call": "2026-04-09T15:00:00Z",
    "voicemail_left": false,
    "person_spoke_with": "Alex",
    "positive_or_negative_contact": "positive",
    "original_appointment": { "date": "2026-04-09", "time": "11:00" },
    "rescheduled_appointment": null,
    "additional_dates_of_service": [],
    "appointment_attendance_status": "attended",
    "reason_why": null,
    "bill_sending_confirmation": "confirmed",
    "report_sending_confirmation": "not_discussed"
  },
  "created_at": "2026-04-09T14:59:30Z",
  "updated_at": "2026-04-09T15:08:30Z"
}

Expanded response with include_call_attempts=true:

{
  "id": "22222222-2222-4222-8222-222222222222",
  "workflow_status": "COMPLETE",
  "best_to_callback_after": null,
  "generated_outcomes": {
    "called": true,
    "time_of_call": "2026-04-09T15:00:00Z",
    "voicemail_left": false,
    "person_spoke_with": "Alex",
    "positive_or_negative_contact": "positive",
    "original_appointment": { "date": "2026-04-09", "time": "11:00" },
    "rescheduled_appointment": null,
    "additional_dates_of_service": [],
    "appointment_attendance_status": "attended",
    "reason_why": null,
    "bill_sending_confirmation": "confirmed",
    "report_sending_confirmation": "not_discussed"
  },
  "call_attempts": [
    {
      "id": "44444444-4444-4444-8444-444444444444",
      "scheduled_request_id": "22222222-2222-4222-8222-222222222222",
      "tenant_id": "tenant_123",
      "attempt_number": 1,
      "status": "COMPLETE",
      "disposition": "ANSWERED",
      "error_detail": null,
      "room_name": "scheduler-tenant_123-22222222",
      "workflow_id": "scheduled-request-tenant_123-22222222-2222-4222-8222-222222222222",
      "call_reference_time_utc": "2026-04-09T15:00:00Z",
      "transcript_bucket": "transcripts",
      "transcript_object_key": "tenant_123/22222222/transcript.json",
      "generated_outcomes": {
        "called": true,
        "time_of_call": "2026-04-09T15:00:00Z",
        "voicemail_left": false,
        "person_spoke_with": "Alex",
        "positive_or_negative_contact": "positive",
        "original_appointment": { "date": "2026-04-09", "time": "11:00" },
        "rescheduled_appointment": null,
        "additional_dates_of_service": [],
        "appointment_attendance_status": "attended",
        "reason_why": null,
        "bill_sending_confirmation": "confirmed",
        "report_sending_confirmation": "not_discussed"
      },
      "agent_behavior_evaluation": null,
      "recording_id": "55555555-5555-4555-8555-555555555555",
      "created_at": "2026-04-09T15:00:00Z",
      "updated_at": "2026-04-09T15:08:30Z"
    }
  ],
  "created_at": "2026-04-09T14:59:30Z",
  "updated_at": "2026-04-09T15:08:30Z"
}

Status mapping

Upstream workflow_status

Local status

ENQUEUED

queued

ACTIVE

calling

COMPLETE

completed

ERROR, CANCELLED, DO_NOT_CALL_BACK

failed or another terminal bucket chosen by the caller

Terminal local statuses are completed and failed. Continue polling until each triggered request is terminal or until the caller's timeout policy is reached.

State to persist

Persist enough state to resume safely:

interface IntegrationCallState {
  external_reference_id: string;
  entity_id?: string;
  request_id?: string;
  request_status: 'not_scheduled' | 'queued' | 'calling' | 'completed' | 'failed';
  last_workflow_status?: string;
  generated_outcomes?: GeneratedOutcomes | null;
}

Idempotency and retry guidance

  • Do not create a second entity for a source row that already has entity_id.

  • Do not schedule a second request for a source row that already has request_id.

  • Do not trigger request IDs that are already calling, completed, or failed.

  • If scheduling partially succeeds, persist successful external_reference_id to id mappings before retrying missing rows.

  • If a trigger call fails or returns errors, retry that single request ID only after confirming it is still ENQUEUED and has no pending attempt.

  • Treat the scheduler request ID as the source of truth after scheduling.

TypeScript direct API example

This example assumes rows are already normalized.

const apiUrl = (process.env.API_URL ?? 'https://agent-api.evergrovelabs.com/').replace(/\/$/, '');
const apiKey = process.env.API_KEY!;

const DEFAULT_WORKING_HOURS_POLICY: WorkingHoursPolicy = {
  monday: { default_call_time: '09:00', windows: [{ start: '09:00', end: '17:00' }] },
  tuesday: { default_call_time: '09:00', windows: [{ start: '09:00', end: '17:00' }] },
  wednesday: { default_call_time: '09:00', windows: [{ start: '09:00', end: '17:00' }] },
  thursday: { default_call_time: '09:00', windows: [{ start: '09:00', end: '17:00' }] },
  friday: { default_call_time: '09:00', windows: [{ start: '09:00', end: '17:00' }] },
  saturday: {},
  sunday: {},
};

async function apiFetch<T>(path: string, init: RequestInit = {}): Promise<T> {
  const response = await fetch(`${apiUrl}${path}`, {
    ...init,
    headers: {
      Accept: 'application/json',
      Authorization: `Bearer ${apiKey}`,
      ...(init.body ? { 'Content-Type': 'application/json' } : {}),
      ...init.headers,
    },
  });

  if (!response.ok) {
    throw new Error(`${path} failed: ${response.status} ${await response.text()}`);
  }

  return response.json() as Promise<T>;
}

function toScheduleRequestCallInput(
  row: NormalizedCallRow,
  entityId: string
): ScheduleRequestCallInput {
  return {
    entity_id: entityId,
    external_reference_id: row.external_reference_id,
    outbound_phone_number: row.outbound_phone_number,
    objective: 'CONFIRM_IE_ATTENDANCE',
    details: {
      organization_name: row.organization_name,
      patient_name: row.patient_name,
      patient_ssn: row.patient_ssn,
      patient_dob: row.patient_dob,
      ...(row.patient_phone_number ? { patient_phone_number: row.patient_phone_number } : {}),
      date_of_injury: row.date_of_injury,
      expected_appointment_date_time: row.expected_appointment_date_time,
      local_timezone: row.local_timezone,
      service_modality: row.service_modality,
      claim_number: row.claim_number,
      insurer_group_name: row.insurer_group_name,
      body_part: row.body_part,
      provider_office: row.provider_office,
      provider_office_address: row.provider_office_address,
      provider_state: row.provider_state,
      eoc_number: row.eoc_number,
    },
  };
}

async function runDirectApiCallFlow(rows: NormalizedCallRow[]) {
  const entityIdByExternalReference: Record<string, string> = {};

  for (const row of rows) {
    const entity = await apiFetch<SchedulerEntity>('/scheduler/entities', {
      method: 'POST',
      body: JSON.stringify({
        name: row.provider_office,
        location_name: row.provider_office,
        location_timezone: row.local_timezone,
        working_hours_policy: DEFAULT_WORKING_HOURS_POLICY,
      } satisfies CreateSchedulerEntityRequest),
    });
    entityIdByExternalReference[row.external_reference_id] = entity.id;
  }

  const scheduleResponse = await apiFetch<ScheduleRequestsResponse>('/scheduler/requests', {
    method: 'POST',
    body: JSON.stringify({
      
      calls: rows.map((row) =>
        toScheduleRequestCallInput(row, entityIdByExternalReference[row.external_reference_id])
      ),
    } satisfies ScheduleRequestsRequest),
  });

  const requestIdByExternalReference = Object.fromEntries(
    scheduleResponse.scheduled_requests.flatMap((request) =>
      request.external_reference_id ? [[request.external_reference_id, request.id]] : []
    )
  );

  const missingRows = rows.filter((row) => !requestIdByExternalReference[row.external_reference_id]);
  if (missingRows.length) {
    throw new Error(
      `Missing scheduler request IDs for ${
        missingRows.map((row) => row.external_reference_id).join(', ')
      }`
    );
  }

  const requestIds = Object.values(requestIdByExternalReference);
  const triggerResponses: TriggerRequestsResponse[] = [];
  for (const requestId of requestIds) {
    triggerResponses.push(
      await apiFetch<TriggerRequestsResponse>('/scheduler/trigger/v2', {
        method: 'POST',
        body: JSON.stringify({
          scheduled_request_ids: [requestId] as [string],
          latency_mode: 'low',
        } satisfies TriggerRequestsRequest),
      })
    );
  }

  return {
    entityIdByExternalReference,
    requestIdByExternalReference,
    triggerResponses,
  };
}

async function pollScheduledRequest(
  requestId: string,
  options: { includeCallAttempts?: boolean } = {}
) {
  const query = options.includeCallAttempts ? '?include_call_attempts=true' : '';
  return apiFetch<ScheduledRequestStatus>(
    `/scheduler/requests/${encodeURIComponent(requestId)}${query}`
  );
}

Integration checklist

  • Build all URLs from API_URL directly.

  • Send Authorization: Bearer {API_KEY} on every API call.

  • Keep one stable external_reference_id per source row.

  • Resolve and persist one entity_id per source row.

  • Schedule requests.

  • Verify the schedule response includes every expected external_reference_id.

  • Trigger scheduled request IDs through /scheduler/trigger/v2, one request ID at a time.

  • Poll request IDs through /scheduler/requests/{requestId} until terminal.

  • Request include_call_attempts=true only when debugging or auditing attempt-level history.

  • Persist entity IDs, request IDs, trigger state, workflow status, and generated outcomes.

Was this helpful?