> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.jelliu.co/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.jelliu.co/_mcp/server.

# Generate a report

POST https://api.jelliu.co/api/reports
Content-Type: application/json

Computes a report over your call or contact data and returns it in `data`, synchronously. The
shape of `data` depends on `type`, and `data.type` echoes it. Use `GET /api/reports/types` for the
catalog. For raw rows instead of aggregates, use `POST /api/exports`.

- `date_from` / `date_to` accept an ISO 8601 datetime (offsets allowed) or a `YYYY-MM-DD` date,
  which means midnight UTC at the start of that day. The range is inclusive on both ends and may
  not exceed 366 days. It is matched against the call's (or contact's) `created_at`.
- `campaign_ids` filters `roi_analysis` and `campaign_comparison`. `contact_funnel` uses only the
  first id, and `cost_per_call` and `agent_performance` ignore it.
- `period` and `format` are validated but change nothing; the response is always JSON.

How each report counts:
- `roi_analysis`: counts only `completed` calls with a duration, so `successfulCalls` always equals
  `totalCalls`. Cost is minutes × Jelliu's internal cost per minute. The human cost is minutes × an
  hourly human-agent rate ÷ 60.
- `campaign_comparison` / `agent_performance`: `successRate` is the percentage of calls in the
  range with status `completed`. Rows are ranked by it, highest first. `agent_performance` credits
  each call to the agent of its campaign, so calls without a campaign are not counted.
- `cost_per_call`: one point per UTC day with completed calls, oldest first. Days without calls are left out.
- `contact_funnel`: contacts created in the range, grouped by status. The known stages (`pending`,
  `called`, `converted`, `dnc`) come first; any other status is appended after them.

**Side effects.** Read-only on your data. The request is written to the audit log as `report.generate`.

**Idempotency.** Safe to retry. Nothing is stored, and the same parameters return the same figures
unless new data arrived.

**Webhook events.** Emits `audit.log_recorded` to webhooks subscribed to it. See [Webhooks](/webhooks).

**Access**
- **Required scope:** `write` (it is a `POST`). Human users need the owner, admin or member role; viewers and billing users are refused.
- **Rate limit:** General API — 120 requests/min per workspace on Starter or with no active plan, 200 on Growth, 300 on Business, 600 on Enterprise. See [Rate limits](/rate-limits).
- **Plan:** Requires the `customReports` plan feature. Every plan includes it today, including workspaces without an active plan, so this gate currently refuses nobody.


Reference: https://developer.jelliu.co/api-reference/reports/post-reports

## Authentication

- `Authorization` header (bearer token, required) — Workspace API key: `jl_` followed by 64 lowercase hex characters, created by the workspace owner in the dashboard (**Settings → API Keys**) and sent as `Authorization: Bearer jl_...`. The plaintext is shown once, at creation; Jelliu stores only a SHA-256 hash. A workspace can hold up to 25 active keys. | Scope | GET / HEAD | POST / PUT / PATCH / DELETE | Admin-only routes | | --- | --- | --- | --- | | `read` | Yes | No | No | | `write` | Yes | Yes | No | | `full` | Yes | Yes | Yes | Operations restricted to admins or owners reject keys without the `full` scope with `403`, and say so in their description. No key, whatever its scope, can mint or revoke API keys or rotate a webhook secret — that requires a signed-in owner session. A revoked key stops authenticating within about 10 seconds. See [Authentication](/authentication).

## Request

### Body (application/json)

This endpoint expects an object.

- `type` (enum, required) — Which report to compute; it decides the shape of `data`. `roi_analysis`: cost, savings vs. human agents and ROI. `campaign_comparison`: campaigns ranked by success rate. `cost_per_call`: daily cost time series. `agent_performance`: agents ranked by success rate. `contact_funnel`: contacts by status and conversion rate.
  - Allowed values: `roi_analysis`, `campaign_comparison`, `cost_per_call`, `agent_performance`, `contact_funnel`
- `period` (enum, required) — Label for the range. Required and validated, but it does not change the computation; only `date_from` / `date_to` do. `daily`, `weekly`, `monthly`, `quarterly` and `custom` behave identically.
  - Allowed values: `daily`, `weekly`, `monthly`, `quarterly`, `custom`
- `date_from` (string, required) — Inclusive start. ISO 8601 datetime (offsets allowed) or `YYYY-MM-DD` (midnight UTC).
- `date_to` (string, required) — Inclusive end. ISO 8601 datetime or `YYYY-MM-DD` (midnight UTC, so the day itself is excluded). At most 366 days after `date_from`.
- `campaign_ids` (list of string, optional) — Restrict to these campaigns. Applied by `roi_analysis` and `campaign_comparison`. `contact_funnel` uses only the first id; the other types ignore it. Each item must be a UUID.
- `format` (enum, optional, default: json) — Accepted for compatibility. The response is always JSON; `pdf` is not rendered.
  - Allowed values: `json`, `pdf`

## Response

### 200

The computed report. The shape of `data` depends on `type`.

- `data` (object or object or object or object or object, required) — One of five report shapes, selected by `type`.
  - RoiAnalysisReport
    - `type` ("roi_analysis", optional)
    - `period` (object, optional) — The `date_from` / `date_to` strings echoed back unchanged.
      - `from` (string, optional)
      - `to` (string, optional)
    - `totalCalls` (integer, optional) — Completed calls with a duration in range.
    - `successfulCalls` (integer, optional) — Always equal to `totalCalls` (only completed calls are counted).
    - `avgDurationSeconds` (double, optional) — Mean call duration, 2 decimals.
    - `totalMinutesUsed` (double, optional) — Sum of durations in minutes, 2 decimals.
    - `costPerMinute` (double, optional) — Jelliu's internal cost per minute (USD), 4 decimals; 0 with no minutes.
    - `totalCost` (double, optional) — Minutes × cost per minute (USD), 2 decimals.
    - `estimatedHumanAgentCost` (double, optional) — Minutes × hourly human-agent rate ÷ 60 (USD), 2 decimals.
    - `savingsVsHuman` (double, optional) — `estimatedHumanAgentCost` − `totalCost` (USD).
    - `roiPercent` (double, optional) — `savingsVsHuman` ÷ `totalCost` × 100, 2 decimals; 0 when there is no cost.
    - `costPerSuccessfulCall` (double, optional) — `totalCost` ÷ `successfulCalls` (USD), 4 decimals.
  - CampaignComparisonReport
    - `type` ("campaign_comparison", optional)
    - `period` (object, optional) — The `date_from` / `date_to` strings echoed back unchanged.
      - `from` (string, optional)
      - `to` (string, optional)
    - `campaigns` (list of object, optional) — Campaigns with at least one call in range, highest success rate first. Deleted campaigns are excluded.
      - `campaignId` (string, optional)
      - `campaignName` (string, optional)
      - `totalCalls` (integer, optional) — Calls of any status in range.
      - `successRate` (double, optional) — Percentage 0-100 of calls that completed, 2 decimals.
      - `avgDurationSeconds` (double, optional)
      - `avgSentiment` (double, optional) — Mean sentiment (-1 to 1); 0 when no call was scored.
      - `totalCost` (double, optional) — Minutes × Jelliu's internal cost per minute (USD).
      - `rank` (integer, optional) — 1-based position by success rate.
  - CostPerCallReport
    - `type` ("cost_per_call", optional)
    - `period` (object, optional) — The `date_from` / `date_to` strings echoed back unchanged.
      - `from` (string, optional)
      - `to` (string, optional)
    - `timeSeries` (list of object, optional) — One point per UTC day with completed calls, oldest first.
      - `date` (string, optional) — UTC day.
      - `totalCost` (double, optional)
      - `callCount` (integer, optional)
      - `costPerCall` (double, optional)
      - `costPerMinute` (double, optional)
    - `totals` (object, optional) — Totals over the whole range.
      - `totalCost` (double, optional)
      - `totalCalls` (integer, optional)
      - `avgCostPerCall` (double, optional)
      - `avgCostPerMinute` (double, optional)
  - AgentPerformanceReport
    - `type` ("agent_performance", optional)
    - `period` (object, optional) — The `date_from` / `date_to` strings echoed back unchanged.
      - `from` (string, optional)
      - `to` (string, optional)
    - `agents` (list of object, optional) — Agents with campaign calls in range, highest success rate first.
      - `agentId` (string, optional)
      - `agentName` (string, optional)
      - `totalCalls` (integer, optional)
      - `successRate` (double, optional) — Percentage 0-100 of calls that completed.
      - `avgDurationSeconds` (double, optional)
      - `avgSentiment` (double, optional)
      - `outcomeBreakdown` (map from string to integer, optional) — Call count per outcome (calls without an outcome are not counted).
      - `rank` (integer, optional)
  - ContactFunnelReport
    - `type` ("contact_funnel", optional)
    - `period` (object, optional) — The `date_from` / `date_to` strings echoed back unchanged.
      - `from` (string, optional)
      - `to` (string, optional)
    - `stages` (list of object, optional) — `pending` always; `called`, `converted`, `dnc` when present; then any other status.
      - `stage` (string, optional)
      - `count` (integer, optional)
      - `percentage` (double, optional) — Share of `totalContacts`, 0-100.
    - `totalContacts` (integer, optional)
    - `conversionRate` (double, optional) — Percentage 0-100 of contacts with status `converted` (any channel).

## Errors

### 400 Bad Request Error

Invalid body. `details` is a Zod `flatten()` object; the date-range check lands in `formErrors`, field errors in `fieldErrors`.

- `error` (object, required) — The error object. Always has `code` and `message`.
  - `code` (string, required) — Stable machine-readable error code (for example `VALIDATION_FAILED`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `BILLING_ERROR`, `COMPLIANCE_BLOCKED`, `RATE_LIMIT_EXCEEDED`, `INTERNAL_ERROR`). Switch on this, not on `message`. See [Errors](/errors).
  - `message` (string, required) — Human-readable explanation. English or Spanish depending on the route; may change without notice.
  - `details` (object or list of object, optional) — Present on `VALIDATION_FAILED` only. Its shape depends on how the route validates: * a field map, either Zod's `flatten()` output (`{ "formErrors": [], "fieldErrors": { "name": ["..."] } }`) or just its `fieldErrors` part (`{ "name": ["..."] }`); * an issue list, where each issue has at least `path`, `message` and `code`. `path` is a dot-separated string on routes that let the schema throw, and an array of keys on routes that forward Zod's raw issues (those also carry Zod's extra issue fields).
    - Field map
      - `formErrors` (list of string, optional)
      - `fieldErrors` (map from string to list of string, optional)
  - `metadata` (map from string to any, optional) — Structured detail exposed for a small allowlist of codes only — for example `BILLING_ERROR` carries `limit`, `current` and `tier` (resource caps) or `tier` and `feature` (feature gates).

### 401 Unauthorized Error

No usable credential. Either the `Authorization` header is missing or is not a well-formed `Bearer jl_…` key, or the key is unknown, revoked or expired. Do not retry with the same key. See [Authentication](/authentication#401-unauthorized).

- `error` (object, required) — The error object. Always has `code` and `message`.
  - `code` (string, required) — Stable machine-readable error code (for example `VALIDATION_FAILED`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `BILLING_ERROR`, `COMPLIANCE_BLOCKED`, `RATE_LIMIT_EXCEEDED`, `INTERNAL_ERROR`). Switch on this, not on `message`. See [Errors](/errors).
  - `message` (string, required) — Human-readable explanation. English or Spanish depending on the route; may change without notice.
  - `details` (object or list of object, optional) — Present on `VALIDATION_FAILED` only. Its shape depends on how the route validates: * a field map, either Zod's `flatten()` output (`{ "formErrors": [], "fieldErrors": { "name": ["..."] } }`) or just its `fieldErrors` part (`{ "name": ["..."] }`); * an issue list, where each issue has at least `path`, `message` and `code`. `path` is a dot-separated string on routes that let the schema throw, and an array of keys on routes that forward Zod's raw issues (those also carry Zod's extra issue fields).
    - Field map
      - `formErrors` (list of string, optional)
      - `fieldErrors` (map from string to list of string, optional)
  - `metadata` (map from string to any, optional) — Structured detail exposed for a small allowlist of codes only — for example `BILLING_ERROR` carries `limit`, `current` and `tier` (resource caps) or `tier` and `feature` (feature gates).

### 403 Forbidden Error

A viewer or billing user, an API key without the `write` scope, a suspended workspace, or a plan without custom reports (not possible today).

- `error` (object, required) — The error object. Always has `code` and `message`.
  - `code` (string, required) — Stable machine-readable error code (for example `VALIDATION_FAILED`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `BILLING_ERROR`, `COMPLIANCE_BLOCKED`, `RATE_LIMIT_EXCEEDED`, `INTERNAL_ERROR`). Switch on this, not on `message`. See [Errors](/errors).
  - `message` (string, required) — Human-readable explanation. English or Spanish depending on the route; may change without notice.
  - `details` (object or list of object, optional) — Present on `VALIDATION_FAILED` only. Its shape depends on how the route validates: * a field map, either Zod's `flatten()` output (`{ "formErrors": [], "fieldErrors": { "name": ["..."] } }`) or just its `fieldErrors` part (`{ "name": ["..."] }`); * an issue list, where each issue has at least `path`, `message` and `code`. `path` is a dot-separated string on routes that let the schema throw, and an array of keys on routes that forward Zod's raw issues (those also carry Zod's extra issue fields).
    - Field map
      - `formErrors` (list of string, optional)
      - `fieldErrors` (map from string to list of string, optional)
  - `metadata` (map from string to any, optional) — Structured detail exposed for a small allowlist of codes only — for example `BILLING_ERROR` carries `limit`, `current` and `tier` (resource caps) or `tier` and `feature` (feature gates).

### 429 Too Many Requests Error

General API rate limit exceeded.

- `error` (object, required) — The error object. Always has `code` and `message`.
  - `code` (string, required) — Stable machine-readable error code (for example `VALIDATION_FAILED`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `BILLING_ERROR`, `COMPLIANCE_BLOCKED`, `RATE_LIMIT_EXCEEDED`, `INTERNAL_ERROR`). Switch on this, not on `message`. See [Errors](/errors).
  - `message` (string, required) — Human-readable explanation. English or Spanish depending on the route; may change without notice.
  - `details` (object or list of object, optional) — Present on `VALIDATION_FAILED` only. Its shape depends on how the route validates: * a field map, either Zod's `flatten()` output (`{ "formErrors": [], "fieldErrors": { "name": ["..."] } }`) or just its `fieldErrors` part (`{ "name": ["..."] }`); * an issue list, where each issue has at least `path`, `message` and `code`. `path` is a dot-separated string on routes that let the schema throw, and an array of keys on routes that forward Zod's raw issues (those also carry Zod's extra issue fields).
    - Field map
      - `formErrors` (list of string, optional)
      - `fieldErrors` (map from string to list of string, optional)
  - `metadata` (map from string to any, optional) — Structured detail exposed for a small allowlist of codes only — for example `BILLING_ERROR` carries `limit`, `current` and `tier` (resource caps) or `tier` and `feature` (feature gates).

## Examples

### roi_analysis

**Request**

```json
undefined
```

**Response**

```json
{
  "data": {
    "avgDurationSeconds": 96.4,
    "costPerMinute": 0.09,
    "costPerSuccessfulCall": 0.1446,
    "estimatedHumanAgentCost": 498.07,
    "period": {
      "from": "2026-08-01T00:00:00Z",
      "to": "2026-08-31T23:59:59Z"
    },
    "roiPercent": 177.79,
    "savingsVsHuman": 318.77,
    "successfulCalls": 1240,
    "totalCalls": 1240,
    "totalCost": 179.3,
    "totalMinutesUsed": 1992.27,
    "type": "roi_analysis"
  }
}
```

**SDK Code**

```python roi_analysis
import requests

url = "https://api.jelliu.co/api/reports"

headers = {"Authorization": "Bearer <token>"}

response = requests.post(url, headers=headers)

print(response.json())
```

```javascript roi_analysis
const url = 'https://api.jelliu.co/api/reports';
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go roi_analysis
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/reports"

	req, _ := http.NewRequest("POST", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby roi_analysis
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/reports")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java roi_analysis
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.jelliu.co/api/reports")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php roi_analysis
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.jelliu.co/api/reports', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp roi_analysis
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/reports");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift roi_analysis
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/reports")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### campaign_comparison

**Request**

```json
undefined
```

**Response**

```json
{
  "data": {
    "campaigns": [
      {
        "avgDurationSeconds": 118.25,
        "avgSentiment": 0.34,
        "campaignId": "0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d",
        "campaignName": "Renovación de pólizas septiembre",
        "rank": 1,
        "successRate": 71.6,
        "totalCalls": 412,
        "totalCost": 73.1
      },
      {
        "avgDurationSeconds": 64.9,
        "avgSentiment": 0.12,
        "campaignId": "4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d",
        "campaignName": "Recordatorio de citas",
        "rank": 2,
        "successRate": 58.33,
        "totalCalls": 288,
        "totalCost": 28.04
      }
    ],
    "period": {
      "from": "2026-09-01",
      "to": "2026-09-15"
    },
    "type": "campaign_comparison"
  }
}
```

**SDK Code**

```python campaign_comparison
import requests

url = "https://api.jelliu.co/api/reports"

headers = {"Authorization": "Bearer <token>"}

response = requests.post(url, headers=headers)

print(response.json())
```

```javascript campaign_comparison
const url = 'https://api.jelliu.co/api/reports';
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go campaign_comparison
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/reports"

	req, _ := http.NewRequest("POST", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby campaign_comparison
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/reports")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java campaign_comparison
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.jelliu.co/api/reports")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php campaign_comparison
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.jelliu.co/api/reports', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp campaign_comparison
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/reports");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift campaign_comparison
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/reports")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### cost_per_call

**Request**

```json
undefined
```

**Response**

```json
{
  "data": {
    "period": {
      "from": "2026-09-12T00:00:00Z",
      "to": "2026-09-14T23:59:59Z"
    },
    "timeSeries": [
      {
        "callCount": 81,
        "costPerCall": 0.1531,
        "costPerMinute": 0.09,
        "date": "2026-09-12",
        "totalCost": 12.4
      },
      {
        "callCount": 66,
        "costPerCall": 0.1495,
        "costPerMinute": 0.09,
        "date": "2026-09-14",
        "totalCost": 9.87
      }
    ],
    "totals": {
      "avgCostPerCall": 0.1515,
      "avgCostPerMinute": 0.09,
      "totalCalls": 147,
      "totalCost": 22.27
    },
    "type": "cost_per_call"
  }
}
```

**SDK Code**

```python cost_per_call
import requests

url = "https://api.jelliu.co/api/reports"

headers = {"Authorization": "Bearer <token>"}

response = requests.post(url, headers=headers)

print(response.json())
```

```javascript cost_per_call
const url = 'https://api.jelliu.co/api/reports';
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go cost_per_call
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/reports"

	req, _ := http.NewRequest("POST", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby cost_per_call
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/reports")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java cost_per_call
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.jelliu.co/api/reports")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php cost_per_call
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.jelliu.co/api/reports', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp cost_per_call
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/reports");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift cost_per_call
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/reports")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### agent_performance

**Request**

```json
undefined
```

**Response**

```json
{
  "data": {
    "agents": [
      {
        "agentId": "2c4e6a8b-0d1f-4e3a-9b5c-7d9e1f3a5b7c",
        "agentName": "Valentina — Cobranza",
        "avgDurationSeconds": 101.3,
        "avgSentiment": 0.21,
        "outcomeBreakdown": {
          "interested": 140,
          "no_answer": 51,
          "not_interested": 96,
          "promise_to_pay": 88
        },
        "rank": 1,
        "successRate": 68.49,
        "totalCalls": 530
      }
    ],
    "period": {
      "from": "2026-09-01",
      "to": "2026-09-15"
    },
    "type": "agent_performance"
  }
}
```

**SDK Code**

```python agent_performance
import requests

url = "https://api.jelliu.co/api/reports"

headers = {"Authorization": "Bearer <token>"}

response = requests.post(url, headers=headers)

print(response.json())
```

```javascript agent_performance
const url = 'https://api.jelliu.co/api/reports';
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go agent_performance
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/reports"

	req, _ := http.NewRequest("POST", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby agent_performance
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/reports")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java agent_performance
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.jelliu.co/api/reports")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php agent_performance
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.jelliu.co/api/reports', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp agent_performance
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/reports");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift agent_performance
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/reports")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### contact_funnel

**Request**

```json
undefined
```

**Response**

```json
{
  "data": {
    "conversionRate": 15,
    "period": {
      "from": "2026-07-01T00:00:00-05:00",
      "to": "2026-09-30T23:59:59-05:00"
    },
    "stages": [
      {
        "count": 120,
        "percentage": 24,
        "stage": "pending"
      },
      {
        "count": 290,
        "percentage": 58,
        "stage": "called"
      },
      {
        "count": 75,
        "percentage": 15,
        "stage": "converted"
      },
      {
        "count": 15,
        "percentage": 3,
        "stage": "dnc"
      }
    ],
    "totalContacts": 500,
    "type": "contact_funnel"
  }
}
```

**SDK Code**

```python contact_funnel
import requests

url = "https://api.jelliu.co/api/reports"

headers = {"Authorization": "Bearer <token>"}

response = requests.post(url, headers=headers)

print(response.json())
```

```javascript contact_funnel
const url = 'https://api.jelliu.co/api/reports';
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go contact_funnel
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/reports"

	req, _ := http.NewRequest("POST", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby contact_funnel
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/reports")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java contact_funnel
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.jelliu.co/api/reports")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php contact_funnel
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.jelliu.co/api/reports', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp contact_funnel
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/reports");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift contact_funnel
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/reports")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### ROI for August

**Request**

```json
{
  "type": "roi_analysis",
  "period": "monthly",
  "date_from": "2026-08-01T00:00:00Z",
  "date_to": "2026-08-31T23:59:59Z"
}
```

**Response**

```json
{
  "data": {
    "avgDurationSeconds": 96.4,
    "costPerMinute": 0.09,
    "costPerSuccessfulCall": 0.1446,
    "estimatedHumanAgentCost": 498.07,
    "period": {
      "from": "2026-08-01T00:00:00Z",
      "to": "2026-08-31T23:59:59Z"
    },
    "roiPercent": 177.79,
    "savingsVsHuman": 318.77,
    "successfulCalls": 1240,
    "totalCalls": 1240,
    "totalCost": 179.3,
    "totalMinutesUsed": 1992.27,
    "type": "roi_analysis"
  }
}
```

**SDK Code**

```python ROI for August
import requests

url = "https://api.jelliu.co/api/reports"

payload = {
    "type": "roi_analysis",
    "period": "monthly",
    "date_from": "2026-08-01T00:00:00Z",
    "date_to": "2026-08-31T23:59:59Z"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript ROI for August
const url = 'https://api.jelliu.co/api/reports';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"type":"roi_analysis","period":"monthly","date_from":"2026-08-01T00:00:00Z","date_to":"2026-08-31T23:59:59Z"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go ROI for August
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/reports"

	payload := strings.NewReader("{\n  \"type\": \"roi_analysis\",\n  \"period\": \"monthly\",\n  \"date_from\": \"2026-08-01T00:00:00Z\",\n  \"date_to\": \"2026-08-31T23:59:59Z\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby ROI for August
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/reports")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"type\": \"roi_analysis\",\n  \"period\": \"monthly\",\n  \"date_from\": \"2026-08-01T00:00:00Z\",\n  \"date_to\": \"2026-08-31T23:59:59Z\"\n}"

response = http.request(request)
puts response.read_body
```

```java ROI for August
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.jelliu.co/api/reports")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"type\": \"roi_analysis\",\n  \"period\": \"monthly\",\n  \"date_from\": \"2026-08-01T00:00:00Z\",\n  \"date_to\": \"2026-08-31T23:59:59Z\"\n}")
  .asString();
```

```php ROI for August
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.jelliu.co/api/reports', [
  'body' => '{
  "type": "roi_analysis",
  "period": "monthly",
  "date_from": "2026-08-01T00:00:00Z",
  "date_to": "2026-08-31T23:59:59Z"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp ROI for August
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/reports");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"type\": \"roi_analysis\",\n  \"period\": \"monthly\",\n  \"date_from\": \"2026-08-01T00:00:00Z\",\n  \"date_to\": \"2026-08-31T23:59:59Z\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift ROI for August
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "type": "roi_analysis",
  "period": "monthly",
  "date_from": "2026-08-01T00:00:00Z",
  "date_to": "2026-08-31T23:59:59Z"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/reports")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Compare two campaigns

**Request**

```json
{
  "type": "campaign_comparison",
  "period": "custom",
  "date_from": "2026-09-01",
  "date_to": "2026-09-15",
  "campaign_ids": [
    "0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d",
    "4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d"
  ]
}
```

**Response**

```json
{
  "data": {
    "avgDurationSeconds": 96.4,
    "costPerMinute": 0.09,
    "costPerSuccessfulCall": 0.1446,
    "estimatedHumanAgentCost": 498.07,
    "period": {
      "from": "2026-08-01T00:00:00Z",
      "to": "2026-08-31T23:59:59Z"
    },
    "roiPercent": 177.79,
    "savingsVsHuman": 318.77,
    "successfulCalls": 1240,
    "totalCalls": 1240,
    "totalCost": 179.3,
    "totalMinutesUsed": 1992.27,
    "type": "roi_analysis"
  }
}
```

**SDK Code**

```python Compare two campaigns
import requests

url = "https://api.jelliu.co/api/reports"

payload = {
    "type": "campaign_comparison",
    "period": "custom",
    "date_from": "2026-09-01",
    "date_to": "2026-09-15",
    "campaign_ids": ["0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d", "4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d"]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Compare two campaigns
const url = 'https://api.jelliu.co/api/reports';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"type":"campaign_comparison","period":"custom","date_from":"2026-09-01","date_to":"2026-09-15","campaign_ids":["0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d","4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d"]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Compare two campaigns
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/reports"

	payload := strings.NewReader("{\n  \"type\": \"campaign_comparison\",\n  \"period\": \"custom\",\n  \"date_from\": \"2026-09-01\",\n  \"date_to\": \"2026-09-15\",\n  \"campaign_ids\": [\n    \"0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d\",\n    \"4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d\"\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Compare two campaigns
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/reports")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"type\": \"campaign_comparison\",\n  \"period\": \"custom\",\n  \"date_from\": \"2026-09-01\",\n  \"date_to\": \"2026-09-15\",\n  \"campaign_ids\": [\n    \"0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d\",\n    \"4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d\"\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java Compare two campaigns
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.jelliu.co/api/reports")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"type\": \"campaign_comparison\",\n  \"period\": \"custom\",\n  \"date_from\": \"2026-09-01\",\n  \"date_to\": \"2026-09-15\",\n  \"campaign_ids\": [\n    \"0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d\",\n    \"4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d\"\n  ]\n}")
  .asString();
```

```php Compare two campaigns
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.jelliu.co/api/reports', [
  'body' => '{
  "type": "campaign_comparison",
  "period": "custom",
  "date_from": "2026-09-01",
  "date_to": "2026-09-15",
  "campaign_ids": [
    "0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d",
    "4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d"
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Compare two campaigns
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/reports");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"type\": \"campaign_comparison\",\n  \"period\": \"custom\",\n  \"date_from\": \"2026-09-01\",\n  \"date_to\": \"2026-09-15\",\n  \"campaign_ids\": [\n    \"0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d\",\n    \"4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d\"\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Compare two campaigns
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "type": "campaign_comparison",
  "period": "custom",
  "date_from": "2026-09-01",
  "date_to": "2026-09-15",
  "campaign_ids": ["0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d", "4d6f8a0c-2e4b-4c6d-8e0f-1a3c5e7a9b2d"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/reports")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Funnel of one campaign

**Request**

```json
{
  "type": "contact_funnel",
  "period": "quarterly",
  "date_from": "2026-07-01T00:00:00-05:00",
  "date_to": "2026-09-30T23:59:59-05:00",
  "campaign_ids": [
    "0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d"
  ]
}
```

**Response**

```json
{
  "data": {
    "avgDurationSeconds": 96.4,
    "costPerMinute": 0.09,
    "costPerSuccessfulCall": 0.1446,
    "estimatedHumanAgentCost": 498.07,
    "period": {
      "from": "2026-08-01T00:00:00Z",
      "to": "2026-08-31T23:59:59Z"
    },
    "roiPercent": 177.79,
    "savingsVsHuman": 318.77,
    "successfulCalls": 1240,
    "totalCalls": 1240,
    "totalCost": 179.3,
    "totalMinutesUsed": 1992.27,
    "type": "roi_analysis"
  }
}
```

**SDK Code**

```python Funnel of one campaign
import requests

url = "https://api.jelliu.co/api/reports"

payload = {
    "type": "contact_funnel",
    "period": "quarterly",
    "date_from": "2026-07-01T00:00:00-05:00",
    "date_to": "2026-09-30T23:59:59-05:00",
    "campaign_ids": ["0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d"]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Funnel of one campaign
const url = 'https://api.jelliu.co/api/reports';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"type":"contact_funnel","period":"quarterly","date_from":"2026-07-01T00:00:00-05:00","date_to":"2026-09-30T23:59:59-05:00","campaign_ids":["0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d"]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Funnel of one campaign
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/reports"

	payload := strings.NewReader("{\n  \"type\": \"contact_funnel\",\n  \"period\": \"quarterly\",\n  \"date_from\": \"2026-07-01T00:00:00-05:00\",\n  \"date_to\": \"2026-09-30T23:59:59-05:00\",\n  \"campaign_ids\": [\n    \"0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d\"\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Funnel of one campaign
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/reports")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"type\": \"contact_funnel\",\n  \"period\": \"quarterly\",\n  \"date_from\": \"2026-07-01T00:00:00-05:00\",\n  \"date_to\": \"2026-09-30T23:59:59-05:00\",\n  \"campaign_ids\": [\n    \"0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d\"\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java Funnel of one campaign
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.jelliu.co/api/reports")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"type\": \"contact_funnel\",\n  \"period\": \"quarterly\",\n  \"date_from\": \"2026-07-01T00:00:00-05:00\",\n  \"date_to\": \"2026-09-30T23:59:59-05:00\",\n  \"campaign_ids\": [\n    \"0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d\"\n  ]\n}")
  .asString();
```

```php Funnel of one campaign
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.jelliu.co/api/reports', [
  'body' => '{
  "type": "contact_funnel",
  "period": "quarterly",
  "date_from": "2026-07-01T00:00:00-05:00",
  "date_to": "2026-09-30T23:59:59-05:00",
  "campaign_ids": [
    "0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d"
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Funnel of one campaign
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/reports");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"type\": \"contact_funnel\",\n  \"period\": \"quarterly\",\n  \"date_from\": \"2026-07-01T00:00:00-05:00\",\n  \"date_to\": \"2026-09-30T23:59:59-05:00\",\n  \"campaign_ids\": [\n    \"0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d\"\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Funnel of one campaign
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "type": "contact_funnel",
  "period": "quarterly",
  "date_from": "2026-07-01T00:00:00-05:00",
  "date_to": "2026-09-30T23:59:59-05:00",
  "campaign_ids": ["0b3e7c52-8d4f-4a11-b2c9-5e6f7a8b9c0d"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/reports")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```