# Reporting API: SparkVault API Reference

> Access analytics, usage metrics, and activity logs for your account. Build dashboards and monitor usage patterns. Usage is tracked but never billed. Subscriptions are billed per license.

Canonical: https://sparkvault.com/api/docs/reporting/ · OpenAPI: https://sparkvault.com/openapi.yaml

## Overview

The Reporting API provides comprehensive analytics and audit data for your SparkVault account. Use it to monitor usage, track consumption, and build custom dashboards.

> **Authentication**
>
> All Reporting endpoints accept standard SparkVault authentication: a session JWT via `Authorization: Bearer …` or an API key via the `X-API-Key` header (API keys are prefixed `sv_live_`). Vault- and ingot-scope audit logs additionally require an unsealed vault session (VAT).

### Available Data

-   **Dashboard Overview**: High-level account metrics at a glance
-   **Usage Over Time**: Time-series data for trend analysis
-   **Activity Feed**: Rolling 24-hour feed of recent operations
-   **Audit Logs**: Durable audit trail across account, integration, vault, and ingot scopes (see the [Audit Logs reference](/api/docs/audit-logs/))
-   **Vault Statistics**: Per-vault usage and storage metrics
-   **API Key Statistics**: Usage metadata per API key
-   **Usage Ledger**: Tracked consumption records (usage is tracked, never billed)

## Dashboard Overview

#### `GET /v1/analytics/overview`

Get high-level account metrics for the dashboard. Returns summary statistics for Sparks, vaults, ingots, transfers, and activity (usage tracked, never billed).

#### Query Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `period` | string | Optional | Reporting window: `day`, `week`, `month` (30 days), or `quarter` (90 days). Omitted or unrecognized values fall back to a 30-day window.Default: `30 days` |

#### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `period` | string | Echo of the requested period; `all` when omitted. |
| `period_start` | integer | Window start (epoch seconds). |
| `period_end` | integer | Window end (epoch seconds). |
| `period_days` | integer | Number of days in the window. |
| `sparks.total` | integer | Total Sparks, all time. |
| `sparks.active` | integer | Live, unread Sparks. |
| `sparks.burned` | integer | Sparks read and destroyed, all time. |
| `sparks.expired` | integer | Sparks that expired unread, all time. |
| `sparks.created_this_period` | integer | Sparks created in the window. |
| `sparks.rate_per_day` | number | Average Sparks created per day in the window. |
| `vaults.total` | integer | Total vaults. |
| `vaults.active` | integer | Active vaults. |
| `vaults.created_this_period` | integer | Vaults created in the window. |
| `vaults.rate_per_day` | number | Average vaults created per day in the window. |
| `ingots.total` | integer | Total ingots across all vaults. |
| `ingots.storage_bytes` | integer | Total storage used across all vaults. |
| `ingots.storage_mb` | number | Total storage in MB. |
| `ingots.storage_gb` | number | Total storage in GB. |
| `transfers.total_access_count` | integer | Total ingot downloads. |
| `transfers.total_bytes` | integer | Bandwidth consumed (uploads + downloads). |
| `transfers.total_mb` | number | Bandwidth consumed in MB. |
| `transfers.total_gb` | number | Bandwidth consumed in GB. |
| `activity.total_operations` | integer | Operations recorded in the window. |
| `activity.operations_per_day` | number | Average operations per day in the window. |

#### Example

Request

```bash
curl "https://api.sparkvault.com/v1/analytics/overview?period=month" \
  -H "X-API-Key: sv_live_YOUR_API_KEY"
```

Response

```json
{
  "data": {
    "period": "month",
    "period_start": 1780358400,
    "period_end": 1782950400,
    "period_days": 30,
    "sparks": {
      "total": 214,
      "active": 12,
      "burned": 187,
      "expired": 15,
      "created_this_period": 42,
      "rate_per_day": 1.4
    },
    "vaults": {
      "total": 5,
      "active": 5,
      "created_this_period": 1,
      "rate_per_day": 0.03
    },
    "ingots": {
      "total": 128,
      "storage_bytes": 10485760,
      "storage_mb": 10,
      "storage_gb": 0.01
    },
    "transfers": {
      "total_access_count": 356,
      "total_bytes": 2576980378,
      "total_mb": 2457.6,
      "total_gb": 2.4
    },
    "activity": {
      "total_operations": 134,
      "operations_per_day": 4.47
    }
  },
  "meta": {
    "api_version": "1.2.828"
  }
}
```

## Usage Over Time

#### `GET /v1/analytics/usage-over-time`

Get time-series usage data for charts and trend analysis. Returns hourly buckets for the day period and daily buckets otherwise.

#### Query Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `period` | string | Optional | Time window: `day` (hourly buckets), `week`, `month` (30 days), `bimonth` (60 days), or `quarter` (90 days).Default: `month` |
| `metric` | string | Optional | Echoed back in the response for chart labeling; it does not filter or change the data. Every data point always includes all four metrics.Default: `operations` |

#### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `period` | string | Requested period. |
| `metric` | string | Echo of the `metric` parameter. |
| `granularity` | integer | Bucket size in seconds: 3600 (hourly) or 86400 (daily). |
| `granularity_label` | string | `hourly` or `daily`. |
| `start_time` | integer | Window start, aligned to the UTC bucket grid (epoch seconds). |
| `end_time` | integer | Window end (epoch seconds). |
| `data_points` | array | One entry per bucket, oldest first. The first and last buckets are partial: they cover only the slice of the window that overlaps them. |
| `data_points[].timestamp` | integer | Bucket start (epoch seconds, UTC-aligned). |
| `data_points[].datetime` | string | ISO 8601 timestamp of the bucket start. |
| `data_points[].operations` | integer | Operations recorded in the bucket. |
| `data_points[].sparks_created` | integer | Sparks created in the bucket. |
| `data_points[].vaults_created` | integer | Vaults created in the bucket. |
| `data_points[].ingots_created` | integer | Ingots created in the bucket. |

#### Example: Sparks Created Per Day

Request

```bash
curl "https://api.sparkvault.com/v1/analytics/usage-over-time?period=week" \
  -H "X-API-Key: sv_live_YOUR_API_KEY"
```

Response

```json
{
  "data": {
    "period": "week",
    "metric": "operations",
    "granularity": 86400,
    "granularity_label": "daily",
    "start_time": 1782345600,
    "end_time": 1782950400,
    "data_points": [
      { "timestamp": 1782345600, "datetime": "2026-06-25T00:00:00.000Z", "operations": 18, "sparks_created": 15, "vaults_created": 0, "ingots_created": 3 },
      { "timestamp": 1782432000, "datetime": "2026-06-26T00:00:00.000Z", "operations": 27, "sparks_created": 23, "vaults_created": 1, "ingots_created": 3 },
      { "timestamp": 1782518400, "datetime": "2026-06-27T00:00:00.000Z", "operations": 20, "sparks_created": 18, "vaults_created": 0, "ingots_created": 2 },
      { "timestamp": 1782604800, "datetime": "2026-06-28T00:00:00.000Z", "operations": 35, "sparks_created": 31, "vaults_created": 0, "ingots_created": 4 },
      { "timestamp": 1782691200, "datetime": "2026-06-29T00:00:00.000Z", "operations": 30, "sparks_created": 27, "vaults_created": 0, "ingots_created": 3 },
      { "timestamp": 1782777600, "datetime": "2026-06-30T00:00:00.000Z", "operations": 14, "sparks_created": 12, "vaults_created": 0, "ingots_created": 2 },
      { "timestamp": 1782864000, "datetime": "2026-07-01T00:00:00.000Z", "operations": 10, "sparks_created": 8, "vaults_created": 0, "ingots_created": 2 },
      { "timestamp": 1782950400, "datetime": "2026-07-02T00:00:00.000Z", "operations": 3, "sparks_created": 2, "vaults_created": 0, "ingots_created": 1 }
    ]
  },
  "meta": {
    "api_version": "1.2.828"
  }
}
```

## Activity Feed

#### `GET /v1/analytics/activity`

Get a rolling feed of recent account activity: usage-ledger operations combined with analytics events (such as Spark reads) from the last 24 hours.

> **24-Hour Window, Not an Audit Log**
>
> The feed always covers the last 24 hours and is assembled from the usage ledger plus analytics events. This is a monitoring convenience, not a compliance-grade audit trail. For the durable, queryable audit trail, use the [Audit Logs API](/api/docs/audit-logs/).

#### Query Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | Optional | Maximum events to return (1-200). Values above 200 are clamped; invalid values fall back to 50.Default: `50` |
| `event_type` | string | Optional | Return only events whose `event_type` exactly matches this value. |
| `period` | string | Optional | Echoed back in the response as-is; the feed window is always the last 24 hours.Default: `day` |

#### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `events` | array | Activity events, newest first. |
| `events[].event_id` | string | Unique event identifier. |
| `events[].event_type` | string | Event type (see Event Types below). |
| `events[].description` | string | Human-readable description of the event. |
| `events[].icon` | string | Display icon for the event. |
| `events[].amount` | string? | Informational usage amount from the ledger entry (dollars string). Present on ledger-backed events only. Usage is tracked, never billed. |
| `events[].reference_id` | string | Related resource reference (e.g. Spark or ingot ID). |
| `events[].vault_id` | string? | Related vault ID on ledger-backed events; null or absent when not applicable. |
| `events[].timestamp` | integer | When the event occurred (epoch seconds). |
| `events[].datetime` | string | ISO 8601 timestamp of the event. |
| `count` | integer | Number of events returned. |
| `period` | string | Echo of the `period` parameter. |
| `filtered_by` | string? | The `event_type` filter that was applied, or null. |

### Event Types

| Type | Description |
| --- | --- |
| `spark_created` | Spark created |
| `vault_created` | Vault created |
| `ingot_created` | Ingot created |
| `ingot_updated` | Ingot updated |

Ledger entries of any other type pass through with their entry type verbatim (e.g. `sparklink_create`, `entropy_generate`), and events sourced from the analytics store (such as Spark reads) carry their stored `event_type` verbatim.

#### Example

Request

```bash
curl "https://api.sparkvault.com/v1/analytics/activity?limit=5" \
  -H "X-API-Key: sv_live_YOUR_API_KEY"
```

Response

```json
{
  "data": {
    "events": [
      {
        "event_id": "TX#1782942000#spk_9f2c4b7e",
        "event_type": "spark_created",
        "description": "Spark created",
        "icon": "⚡",
        "amount": "0.00",
        "reference_id": "spk_9f2c4b7e",
        "vault_id": null,
        "timestamp": 1782942000,
        "datetime": "2026-07-01T21:40:00.000Z"
      },
      {
        "event_id": "TX#1782938400#ing_5d8a1c3f",
        "event_type": "ingot_created",
        "description": "Ingot created",
        "icon": "📦",
        "amount": "0.00",
        "reference_id": "ing_5d8a1c3f",
        "vault_id": "vlt_7b2e9d4a",
        "timestamp": 1782938400,
        "datetime": "2026-07-01T20:40:00.000Z"
      }
    ],
    "count": 2,
    "period": "day",
    "filtered_by": null
  },
  "meta": {
    "api_version": "1.2.828"
  }
}
```

## Audit Logs

The durable, queryable audit trail is the Audit Logs API. It records events at four scopes (account, integration, vault, and ingot) with signed cursor pagination and event-type filtering. Full parameters, response shapes, and event types are documented in the [Audit Logs reference](/api/docs/audit-logs/).

#### `GET /v1/audit-logs`

List account-scope audit logs.

#### `GET /v1/audit-logs/apps/{app_slug}`

List audit logs for a specific integration.

#### `POST /v1/audit-logs/apps`

Record an integration-scope audit event.

#### `GET /v1/vaults/{vault_id}/audit-logs`

List vault-scope audit logs. Requires an unsealed vault session (VAT).

#### `GET /v1/vaults/{vault_id}/ingots/{ingot_id}/audit-logs`

List per-ingot audit logs. Requires an unsealed vault session (VAT).

All list endpoints accept `limit` (1-100, default 25), `cursor` (the signed `next_cursor` from the previous page, bound to your account and audit scope), and `event_types` (comma-separated filter). Entries include a resolved `actor_type` (`user` or `api_key`) and `actor_display` (email or key name), and the account, vault, and ingot list responses include the valid event types for their scope. `POST /v1/audit-logs/apps` takes `app_slug`, `event_type`, and optional `metadata` in the request body.

## Spark Activity

#### `GET /v1/analytics/spark-activity`

Get Spark creation counts as a time series. Counts are derived from the usage ledger, so they remain accurate after Spark records expire.

#### Query Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `days` | integer | Optional | Window size in days (1-365). `days=1` returns hourly buckets; anything larger returns daily buckets. Invalid values fall back to 7.Default: `7` |

#### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `days` | integer | Number of days covered. |
| `type` | string | `hourly` (when `days=1`) or `daily`. |
| `total_sparks` | integer | Total Sparks created in the window. |
| `hourly_activity` | array | Hourly buckets of `{hour, count}`, oldest first (`hour` 23 is the current hour). Present when type is `hourly`. |
| `daily_activity` | array | Daily buckets of `{date, count}` with `date` as YYYY-MM-DD, oldest first. Includes today, so a 7-day request returns 8 entries. Present when type is `daily`. |
| `start_date` | string | First date in the window (daily responses only). |
| `end_date` | string | Last date in the window (daily responses only). |

## Vault Statistics

#### `GET /v1/analytics/vaults/{vault_id}`

Get detailed statistics for a specific vault, including storage usage and ingot metrics.

#### Query Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `period` | string | Optional | Activity window: `day`, `week`, or `month`. Any other value widens the window to the vault's full history.Default: `month` |

#### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `vault.vault_id` | string | Vault identifier. |
| `vault.name` | string | Vault name. |
| `vault.status` | string | Vault status. |
| `vault.created_at` | integer | Creation timestamp (epoch seconds). |
| `statistics.total_ingots` | integer | Number of ingots in the vault. |
| `statistics.ingots_created_this_period` | integer | Ingots created in the window. |
| `statistics.total_storage_bytes` | integer | Total storage used by the vault. |
| `statistics.total_storage_gb` | string | Total storage in GB, two decimal places. |
| `statistics.average_ingot_size_bytes` | integer | Average ingot size. |
| `statistics.large_ingots_count` | integer | Ingots held in object storage. |
| `statistics.small_ingots_count` | integer | Ingots stored inline. |
| `statistics.last_unsealed_at` | integer? | Last unseal timestamp; null if the vault has never been unsealed. |
| `statistics.unseal_count` | integer | Number of times the vault has been unsealed. |
| `activity.period` | string | Echo of the `period` parameter. |
| `activity.ingots_created` | integer | Ingots created in the window. |
| `activity.storage_added_bytes` | integer | Storage added in the window. |

## API Key Statistics

#### `GET /v1/analytics/api-keys/{api_key_id}`

Get usage statistics for a specific API key, derived from the key record.

> **Request-Level Metrics**
>
> Per-request counts and top-endpoint breakdowns are not part of this endpoint. Statistics are derived from the key record's creation and last-used timestamps, and the response carries a fixed `note` saying so.

#### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `api_key.api_key_id` | string | API key identifier. |
| `api_key.name` | string | API key name. |
| `api_key.key_preview` | string | Redacted key preview (e.g. `sv_live_***`). |
| `api_key.status` | string | Key status. |
| `api_key.created_at` | integer | Creation timestamp (epoch seconds). |
| `usage.last_used_at` | integer? | Last usage timestamp; null if the key has never been used. |
| `usage.days_since_last_used` | integer? | Days since last use; null if the key has never been used. |
| `usage.days_since_creation` | integer | Days since the key was created. |
| `usage.is_active` | boolean | True when the key was used within the last 30 days. |
| `note` | string | Fixed notice that per-request logging is not included. |

## Usage Ledger

The usage ledger records consumption events (operations and transfers) for your account. Usage is tracked, never billed. Subscriptions are billed per license via Stripe invoices. Use this to attribute usage to vaults and operations.

#### `GET /v1/billing/transactions`

Get the usage ledger for your account. Each entry records a tracked operation or transfer. Individual entries that were rolled up into aggregate summaries are hidden by default.

#### Query Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | Optional | Maximum results (1-1000). Invalid values fall back to 1000.Default: `1000` |
| `type` | string | Optional | Filter by ledger entry type (e.g. `spark_create`). Ignored when `start_date` is a YYYY-MM-DD date. Combine it with epoch `start_date` filtering or no date filter. |
| `category` | string | Optional | Filter by category (maps to entry types, e.g. `Sparks Created`). |
| `start_date` | string | Optional | Start of range: epoch timestamp or YYYY-MM-DD. |
| `end_date` | string | Optional | End of range (YYYY-MM-DD). Honored only when `start_date` is also a YYYY-MM-DD date; ignored with epoch filtering. Defaults to the same day as `start_date`. |
| `include_aggregated` | string | Optional | Set to `true` to include individual entries that were rolled up into aggregate summaries; they are filtered out by default. |

#### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `transactions` | array | Array of usage ledger entries. |
| `transactions[].type` | string | Ledger entry type (e.g. `spark_create`, `entropy_generate`, `Ingot Transfer - Forge Encryption`). |
| `transactions[].amount` | string | Informational cost recorded for the entry (dollars string, zero or negative). Usage is tracked, never billed. |
| `transactions[].name` | string? | Resource name, if applicable. |
| `transactions[].description` | string? | Human-readable description, if set. |
| `transactions[].vault_id` | string? | Related vault ID, if applicable. |
| `transactions[].reference_id` | string | Related resource reference (also the entry's idempotency key). |
| `transactions[].created_at` | integer | Entry timestamp (epoch seconds). |
| `transactions[].operation_count` | integer? | Number of operations rolled into an aggregated summary entry; null on individual entries. |
| `transactions[].period_start` | integer? | Start of the window covered by an aggregated summary entry; null on individual entries. |
| `transactions[].period_end` | integer? | End of the window covered by an aggregated summary entry; null on individual entries. |
| `count` | integer | Number of entries returned. |

#### Example

Request

```bash
curl "https://api.sparkvault.com/v1/billing/transactions?limit=5" \
  -H "X-API-Key: sv_live_YOUR_API_KEY"
```

Response

```json
{
  "data": {
    "transactions": [
      {
        "type": "spark_create",
        "amount": "0.00",
        "reference_id": "spk_9f2c4b7e",
        "vault_id": null,
        "name": null,
        "description": null,
        "created_at": 1782942000,
        "operation_count": null,
        "period_start": null,
        "period_end": null
      },
      {
        "type": "entropy_generate",
        "amount": "0.00",
        "reference_id": "ent_a1b2c3d4",
        "vault_id": null,
        "name": null,
        "description": null,
        "created_at": 1782938400,
        "operation_count": null,
        "period_start": null,
        "period_end": null
      }
    ],
    "count": 2
  },
  "meta": {
    "api_version": "1.2.828"
  }
}
```

### Related Endpoints

#### `GET /v1/billing/summaries`

List pre-aggregated daily usage summaries.

Accepts `start_date` / `end_date` (YYYY-MM-DD, defaults to the last 30 days) and `category`. Returns one row per day and category (`date`, `category`, `total_charges`, `transaction_count`, `total_bytes`) plus period totals.

#### `GET /v1/billing/usage/breakdown`

Per-member storage and per-vault bandwidth attribution, derived from the account's ingot records. Admin-only.

Returns `by_member` (storage attributed to the member who uploaded each ingot) and `by_vault` (transfer bandwidth attributed to the vault itself), plus a `truncated` flag when a very large account exceeds the scan cap.

## Error Reference

#### Error Responses

| Status | Code | Description |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | Invalid query parameters |
| 401 | `AUTHENTICATION_ERROR` | Invalid or missing authentication |
| 403 | `FORBIDDEN` | Insufficient permissions for this resource |
| 404 | `NOT_FOUND` | Resource not found |
