> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gomobile.ma/llms.txt
> Use this file to discover all available pages before exploring further.

# Call Reports

> Detailed reports for individual calls and call jobs

Query reports for call requests, including all attempts, events, and flow execution details.

<Info>
  **Base path: `/call-report`**
</Info>

***

## Types

<Accordion title="Type Definitions">
  ```typescript theme={null}
  // ============================================
  // JOB STATUS
  // ============================================

  type JobStatus = 'queued' | 'active' | 'completed' | 'failed';

  // ============================================
  // CALL DETAILS
  // ============================================

  interface CallDetails {
    status: string;
    direction: 'inbound' | 'outbound';
    from: string;
    to: string;
    createdAt: string;       // ISO date
    dialedAt?: string;       // ISO date
    answeredAt?: string;     // ISO date
    terminatedAt?: string;   // ISO date
    durationMs?: number;
  }

  // ============================================
  // NODE EXECUTION PATH ENTRY
  // ============================================

  interface NodeExecutionPathEntry {
    nodeId: string;
    nodeType: string;       // 'dial' | 'play' | 'dtmf' | 'record' | 'condition' | 'set_variable' | 'hangup' | 'answer'
    nodeLabel?: string;
    outputPath?: string;    // Which output was taken (e.g., 'onAnswer', 'onBusy', 'onComplete')
    timestamp: string;      // ISO date
  }

  // ============================================
  // FLOW EXECUTION DETAILS
  // ============================================

  interface FlowExecutionDetails {
    flowId: string;
    flowName: string;
    flowVersion: number;
    executionPath: NodeExecutionPathEntry[];
    finalVariables: Record<string, string | number | boolean | null>;
    nodeExecutionCount: number;
    flowStartedAt?: string;            // ISO date
    flowCompletedAt?: string;          // ISO date
  }

  // ============================================
  // NODE CONTEXT (embedded in event data)
  // ============================================

  interface NodeContext {
    nodeId: string;
    nodeType: string;
    nodeExecutionIndex: number;
  }

  // ============================================
  // CALL EVENT
  // ============================================

  interface CallEvent {
    type: string;                      // 'dial' | 'answer' | 'play' | 'record' | 'dtmf' | 'hangup' | etc.
    timestamp: string;                 // ISO date
    data: Record<string, unknown>;     // Includes nodeContext when applicable
  }

  // ============================================
  // CALL BILLING
  // ============================================

  interface NodeCostReport {
    nodeId: string;
    nodeType: string;
    durationMs: number | null;
    cost: number;
    costPerUnit: number;
    unit: 'second' | 'minute' | 'flat';
    minDurationMs: number | null;
  }

  interface CallBillingReport {
    nodes: NodeCostReport[];
    totalCost: number;
  }

  // ============================================
  // CALL ATTEMPT REPORT
  // ============================================

  interface CallAttemptReport {
    /** Unique call ID (UUID) */
    callId: string;

    /** Attempt number (1-based) */
    attempt: number;

    /** Business context (if from program execution) */
    programId?: string;
    programExecutionId?: string;
    contactId?: string;

    /** Call metadata */
    call: CallDetails;

    /** Final outcome */
    outcome: string;

    /** Human-readable reason */
    outcomeReason?: string;

    /** Flow execution details (if flow was executed) */
    flowExecution?: FlowExecutionDetails;

    /** Billing breakdown (only for completed calls with cost) */
    billing?: CallBillingReport;

    /** Events timeline */
    events: CallEvent[];
  }

  // ============================================
  // JOB REPORT
  // ============================================

  interface JobReport {
    /** Job ID (UUID from POST /call-requests) */
    jobId: string;

    /** Current job status */
    status: JobStatus;

    /** Final outcome (from last attempt) */
    finalOutcome?: string;

    /** All call attempts */
    attempts: CallAttemptReport[];
  }
  ```
</Accordion>

***

### Get full report for a call request job

Completed job with retry (first attempt busy, second answered):

```json theme={null}
{
  "jobId": "ec8edce0-f898-4d34-b2fc-542ef98f38a5",
  "status": "completed",
  "finalOutcome": "completed",
  "attempts": [
    {
      "callId": "1cbdf482-4dac-41ed-a430-2e311add389d",
      "attempt": 1,
      "call": {
        "status": "busy",
        "direction": "outbound",
        "from": "1000",
        "to": "6001",
        "createdAt": "2025-12-16T11:15:00.062Z",
        "dialedAt": "2025-12-16T11:15:00.103Z",
        "terminatedAt": "2025-12-16T11:15:07.352Z"
      },
      "outcome": "busy",
      "outcomeReason": "Flow completed (Error in dial node: Remote hangup for call ...: busy (cause: 17, code: 17))",
      "flowExecution": {
        "flowId": "03418632-e6da-451e-875f-23b55f938e3e",
        "flowName": "credit-dtmf-playback-test",
        "flowVersion": 1,
        "executionPath": [
          {
            "nodeId": "dial-1",
            "nodeType": "dial",
            "nodeLabel": "Dial Contact",
            "timestamp": "2025-12-16T11:15:00.071Z",
            "outputPath": "onBusy"
          },
          {
            "nodeId": "hangup-1",
            "nodeType": "hangup",
            "nodeLabel": "End Call",
            "timestamp": "2025-12-16T11:15:07.333Z",
            "outputPath": "terminated"
          }
        ],
        "finalVariables": {
          "contact.id": "6fd21c0b-bf05-407e-bcd7-9f9aab7ab91e",
          "sys.callId": "1cbdf482-4dac-41ed-a430-2e311add389d",
          "sys.attempt": 1,
          "sys.maxAttempts": 3,
          "contact.phone": "6001",
          "contact.fullName": "dev-anouar-1",
          "contact.customAttributes.credit": 90856
        },
        "nodeExecutionCount": 2,
        "flowStartedAt": "2025-12-16T11:15:00.070Z",
        "flowCompletedAt": "2025-12-16T11:15:07.352Z"
      },
      "events": [
        {
          "type": "dial",
          "timestamp": "2025-12-16T11:15:00.072Z",
          "data": {
            "to": "6001",
            "from": "1000",
            "timeout": 30000,
            "enableAMD": false,
            "nodeContext": {
              "nodeId": "dial-1",
              "nodeType": "dial",
              "nodeExecutionIndex": 2
            }
          }
        },
        {
          "type": "hangup",
          "timestamp": "2025-12-16T11:15:07.352Z",
          "data": {
            "hangupType": "busy",
            "hangupReason": "Flow completed (...)",
            "nodeContext": {
              "nodeId": "hangup-1",
              "nodeType": "hangup",
              "nodeExecutionIndex": 3
            }
          }
        }
      ]
    },
    {
      "callId": "eae26ac8-be39-490b-b9ed-a82e7f4048f6",
      "attempt": 2,
      "call": {
        "status": "completed",
        "direction": "outbound",
        "from": "1000",
        "to": "6001",
        "createdAt": "2025-12-16T11:15:30.105Z",
        "dialedAt": "2025-12-16T11:15:30.139Z",
        "answeredAt": "2025-12-16T11:15:34.479Z",
        "durationMs": 7757
      },
      "outcome": "completed",
      "flowExecution": {
        "flowId": "03418632-e6da-451e-875f-23b55f938e3e",
        "flowName": "credit-dtmf-playback-test",
        "flowVersion": 1,
        "executionPath": [
          {
            "nodeId": "dial-1",
            "nodeType": "dial",
            "nodeLabel": "Dial Contact",
            "timestamp": "2025-12-16T11:15:30.114Z",
            "outputPath": "onAnswer"
          },
          {
            "nodeId": "play-credit",
            "nodeType": "play",
            "nodeLabel": "Play Credit Balance",
            "timestamp": "2025-12-16T11:15:34.481Z",
            "outputPath": "onComplete"
          }
        ],
        "finalVariables": {
          "answeredBy": "human",
          "sys.attempt": 2,
          "sys.maxAttempts": 3,
          "contact.customAttributes.credit": 90856
        },
        "nodeExecutionCount": 2,
        "flowStartedAt": "2025-12-16T11:15:30.113Z"
      },
      "events": [
        {
          "type": "dial",
          "timestamp": "2025-12-16T11:15:30.115Z",
          "data": {
            "to": "6001",
            "from": "1000",
            "timeout": 30000,
            "enableAMD": false,
            "nodeContext": {
              "nodeId": "dial-1",
              "nodeType": "dial",
              "nodeExecutionIndex": 2
            }
          }
        },
        {
          "type": "answer",
          "timestamp": "2025-12-16T11:15:34.479Z",
          "data": {
            "answeredBy": "human",
            "ringDurationMs": 4340,
            "nodeContext": {
              "nodeId": "dial-1",
              "nodeType": "dial",
              "nodeExecutionIndex": 2
            }
          }
        },
        {
          "type": "play",
          "timestamp": "2025-12-16T11:15:42.231Z",
          "data": {
            "durationMs": 6420,
            "bufferCount": 2,
            "completedBy": "stopped",
            "nodeContext": {
              "nodeId": "play-credit",
              "nodeType": "play",
              "nodeExecutionIndex": 3
            }
          }
        }
      ]
    }
  ]
}
```

Queued job (not yet executed):

```json theme={null}
{
  "jobId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "queued",
  "attempts": []
}
```

**Error Responses:**

| Code | Error               | Description                                                   |
| ---- | ------------------- | ------------------------------------------------------------- |
| 404  | `NotFoundException` | Job not found (invalid jobId or job cleaned up with no calls) |

***

### Get detailed report for a single call

**Example Response:**

```json theme={null}
{
  "callId": "60e8fbc0-2cda-4b2e-bc0f-221c3121bf09",
  "attempt": 1,
  "programId": "abc12345-1234-5678-9012-abcdef123456",
  "programExecutionId": "exec-9876-5432-1098-fedcba987654",
  "contactId": "6fd21c0b-bf05-407e-bcd7-9f9aab7ab91e",
  "call": {
    "status": "completed",
    "direction": "outbound",
    "from": "1000",
    "to": "6001",
    "createdAt": "2025-12-18T14:17:32.736Z",
    "dialedAt": "2025-12-18T14:17:32.800Z",
    "answeredAt": "2025-12-18T14:17:36.100Z",
    "terminatedAt": "2025-12-18T14:18:01.134Z",
    "durationMs": 25001
  },
  "outcome": "completed",
  "outcomeReason": "Flow completed successfully",
  "flowExecution": {
    "flowId": "03418632-e6da-451e-875f-23b55f938e3e",
    "flowName": "credit-dtmf-playback-test",
    "flowVersion": 1,
    "executionPath": [
      {
        "nodeId": "dial-1",
        "nodeType": "dial",
        "nodeLabel": "Dial Contact",
        "timestamp": "2025-12-18T14:17:32.740Z",
        "outputPath": "onAnswer"
      },
      {
        "nodeId": "play-credit",
        "nodeType": "play",
        "nodeLabel": "Play Credit Balance",
        "timestamp": "2025-12-18T14:17:36.105Z",
        "outputPath": "onComplete"
      }
    ],
    "finalVariables": {
      "contact.id": "6fd21c0b-bf05-407e-bcd7-9f9aab7ab91e",
      "sys.callId": "60e8fbc0-2cda-4b2e-bc0f-221c3121bf09",
      "sys.attempt": 1,
      "contact.customAttributes.credit": 90856
    },
    "nodeExecutionCount": 2,
    "flowStartedAt": "2025-12-18T14:17:32.738Z",
    "flowCompletedAt": "2025-12-18T14:18:01.134Z"
  },
  "billing": {
    "nodes": [
      {
        "nodeId": "dial-1",
        "nodeType": "dial",
        "durationMs": 25001,
        "cost": 1.875075,
        "costPerUnit": 0.075,
        "unit": "second",
        "minDurationMs": 10000
      }
    ],
    "totalCost": 1.875075
  },
  "events": [
    {
      "type": "dial",
      "timestamp": "2025-12-18T14:17:32.741Z",
      "data": {
        "to": "6001",
        "from": "1000",
        "timeout": 30000,
        "nodeContext": { "nodeId": "dial-1", "nodeType": "dial", "nodeExecutionIndex": 1 }
      }
    },
    {
      "type": "answer",
      "timestamp": "2025-12-18T14:17:36.100Z",
      "data": {
        "answeredBy": "human",
        "ringDurationMs": 3300,
        "nodeContext": { "nodeId": "dial-1", "nodeType": "dial", "nodeExecutionIndex": 1 }
      }
    },
    {
      "type": "play",
      "timestamp": "2025-12-18T14:17:58.500Z",
      "data": {
        "durationMs": 22000,
        "completedBy": "stopped",
        "nodeContext": { "nodeId": "play-credit", "nodeType": "play", "nodeExecutionIndex": 2 }
      }
    }
  ]
}
```

**Note:** `programId`, `programExecutionId`, and `contactId` are populated when the call was made through a program execution. They are `undefined` for direct call-request API calls.

**Error Responses:**

| Code | Error               | Description                                       |
| ---- | ------------------- | ------------------------------------------------- |
| 404  | `NotFoundException` | Call not found or does not belong to organization |

***

## Event Types

***

## Notes

* Report works even if BullMQ job has been cleaned up (call data persisted in DB)
* `attempts` array is ordered by attempt number (1, 2, 3...)
* `status` is derived from BullMQ state if available, otherwise from call outcomes
* `finalOutcome` is the outcome of the last attempt
* `executionPath` shows exact nodes executed with their output paths
* `events` include `nodeContext` to correlate with flow execution
* Works for both ad-hoc calls (via `/call-requests`) and program calls
