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

# Data Structures

> Canonical data models for accounts, capabilities, posts, slideshows, analytics, and more returned by the Genviral social media API.

> Canonical objects returned by the Genviral Partner API. These structures are designed for easy consumption by OpenClaw agents, AI automation pipelines, and custom integrations.

## Partner API Key

Represents the credential you create in **API Keys**. Every key is single-scope:
either `workspace` or `personal`.

| Field           | Type                | Description                                                    |
| --------------- | ------------------- | -------------------------------------------------------------- |
| `public_id`     | `string`            | Short identifier (e.g., `gva_live_2ff93c`).                    |
| `secret_suffix` | `string`            | Last four characters of the secret portion, useful for audits. |
| `scope`         | `string`            | `workspace` or `personal`.                                     |
| `workspace_id`  | `string \| null`    | Present for workspace keys.                                    |
| `owner_user_id` | `string \| null`    | Present for personal keys.                                     |
| `is_active`     | `boolean`           | Key active state.                                              |
| `created_at`    | `string (ISO 8601)` | Timestamp when the key was issued.                             |
| `last_used_at`  | `string \| null`    | Updated whenever the key is used.                              |
| `revoked_at`    | `string \| null`    | Timestamp when key was revoked.                                |

```json theme={null}
{
  "public_id": "gva_live_2ff93c",
  "secret_suffix": "b4d5",
  "scope": "personal",
  "workspace_id": null,
  "owner_user_id": "5ec8f2fd-8d0a-4c68-b05d-9a8a85aa5d5d",
  "is_active": true,
  "created_at": "2026-02-13T15:32:11.402Z",
  "last_used_at": "2026-02-13T18:14:03.009Z",
  "revoked_at": null
}
```

## Social Account (BYO + Hosted)

Returned by `GET /accounts` and referenced when scheduling posts. Account IDs are UUIDs.

| Field          | Type             | Description                                                                                                        |
| -------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| `id`           | `string (UUID)`  | Scope-constrained account identifier.                                                                              |
| `platform`     | `string`         | `tiktok`, `instagram`, etc.                                                                                        |
| `type`         | `string`         | `byo` (user-connected) or `hosted` (Genviral-managed).                                                             |
| `username`     | `string`         | Handle shown on the platform.                                                                                      |
| `display_name` | `string`         | Friendly label surfaced in the dashboard.                                                                          |
| `status`       | `string`         | `active`, `paused`, `revoked`, etc.                                                                                |
| `workspace_id` | `string \| null` | Workspace owner when account is workspace-scoped; `null` in personal scope.                                        |
| `capabilities` | `object`         | Per-account supported content kinds, caption/media limits, unsupported reasons, and provider settings JSON Schema. |

```json theme={null}
{
  "id": "0f4f54d4-8cce-4fb7-8c7b-befbcb8af812",
  "platform": "tiktok",
  "type": "hosted",
  "username": "ugc_trends_42",
  "display_name": "Hosted Trends 42",
  "status": "active",
  "workspace_id": "4cb5d3fd-8c8f-4ed7-a17c-4ffb52c7e6ac",
  "capabilities": {
    "supported_content_kinds": ["single_image", "multi_image", "single_video"],
    "caption_limit": 500,
    "media_limits": {
      "max_images": 35,
      "max_videos": 1
    },
    "unsupported_content_kind_reasons": {
      "text_only": "Text-only posts are only available for connected BYO accounts; hosted accounts require media."
    },
    "settings_schema": {
      "type": "object",
      "additionalProperties": false,
      "properties": {}
    }
  }
}
```

### Account Capabilities

Returned under `account.capabilities` by `GET /accounts`.

| Field                              | Type       | Description                                                                                                       |
| ---------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------- |
| `supported_content_kinds`          | `string[]` | Content kinds this account supports through Genviral: `text_only`, `single_image`, `multi_image`, `single_video`. |
| `caption_limit`                    | `number`   | Account-aware caption limit.                                                                                      |
| `media_limits.max_images`          | `number`   | Maximum image count accepted for the account/platform.                                                            |
| `media_limits.max_videos`          | `number`   | Maximum video count accepted for the account/platform.                                                            |
| `media_limits.max_video_seconds`   | `number`   | Optional max video duration when the platform/account policy needs it.                                            |
| `unsupported_content_kind_reasons` | `object`   | Reason strings keyed by unsupported content kind.                                                                 |
| `settings_schema`                  | `object`   | JSON Schema for provider settings under `settings.<provider>`.                                                    |

## Post

Created via `POST /posts`, retrieved via `GET /posts` and `GET /posts/{id}`.

| Field          | Type             | Description                                                                                                |
| -------------- | ---------------- | ---------------------------------------------------------------------------------------------------------- |
| `id`           | `string (UUID)`  | Unique post ID.                                                                                            |
| `status`       | `string`         | `draft`, `pending`, `scheduled`, `retry`, `posted`, `failed`, `partial`, `canceled`, `deleted`, `expired`. |
| `caption`      | `string`         | Cross-platform caption.                                                                                    |
| `scheduled_at` | `string \| null` | Target publish timestamp.                                                                                  |
| `created_at`   | `string`         | ISO timestamp when the post was created.                                                                   |
| `accounts`     | `object`         | Summary + per-account states (see below).                                                                  |
| `media`        | `object \| null` | Mirrors the create/update payload (`type` + `url`/`urls`), or `null` for text-only posts.                  |
| `music_url`    | `string \| null` | TikTok post URL applied to the TikTok audio track. Not supported for Instagram targets.                    |
| `tiktok`       | `object \| null` | Optional TikTok publish settings (only for TikTok BYO-targeted posts).                                     |
| `pinterest`    | `object \| null` | Optional Pinterest settings (`board_id`, `link`, `title`, `tags`).                                         |

```json theme={null}
{
  "id": "11111111-1111-1111-1111-111111111111",
  "caption": "Holiday drops start Monday!",
  "status": "scheduled",
  "scheduled_at": "2025-02-01T15:00:00Z",
  "created_at": "2025-01-20T12:05:11.205Z",
  "tiktok": {
    "post_mode": "MEDIA_UPLOAD",
    "privacy_level": "PUBLIC_TO_EVERYONE"
  }
}
```

Top-level `tiktok` and `pinterest` settings are v1 convenience aliases.
New multi-platform clients should prefer canonical provider settings under
`settings.<provider>` in create/update requests.

### Media

Returned as submitted to `POST /posts` and `PATCH /posts/{id}`, or `null` for
text-only posts:

| Field  | Type       | Description                                                                 |
| ------ | ---------- | --------------------------------------------------------------------------- |
| `type` | `string`   | `video` or `slideshow`. Determines which property appears below.            |
| `url`  | `string`   | Present when `type="video"`. Points to the ingested/validated clip.         |
| `urls` | `string[]` | Present when `type="slideshow"`. Ordered list of image URLs (1–35 entries). |

When BYO accounts are present, Genviral re-hosts the assets behind the scenes so
these URLs point to first-party Cloudflare R2 buckets. Hosted-only posts reuse
the URLs you provided once reachability is confirmed.

### TikTok Settings

Optional settings persisted from `POST /posts` / `PATCH /posts/{id}` under the
`tiktok` field. These apply only when all targeted accounts are TikTok BYO
accounts.

| Field                      | Type      | Description                                                                                                                                                                                                                               |
| -------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `title`                    | `string`  | Optional TikTok title override. Video posts: max 2,200 UTF-16 runes. Photo/slideshow posts: max 90 UTF-16 runes.                                                                                                                          |
| `description`              | `string`  | Optional TikTok description override. Photo/slideshow posts: max 4,000 UTF-16 runes. For video posts, Genviral keeps this field for compatibility and can use it as a fallback source when deriving the TikTok title if `title` is blank. |
| `post_mode`                | `string`  | `DIRECT_POST` or `MEDIA_UPLOAD` (TikTok inbox/drafts).                                                                                                                                                                                    |
| `privacy_level`            | `string`  | TikTok privacy level (`PUBLIC_TO_EVERYONE`, `MUTUAL_FOLLOW_FRIENDS`, `FOLLOWER_OF_CREATOR`, `SELF_ONLY`).                                                                                                                                 |
| `disable_comment`          | `boolean` | Optional comment toggle.                                                                                                                                                                                                                  |
| `disable_duet`             | `boolean` | Optional duet toggle (video posts).                                                                                                                                                                                                       |
| `disable_stitch`           | `boolean` | Optional stitch toggle (video posts).                                                                                                                                                                                                     |
| `video_cover_timestamp_ms` | `integer` | Optional video cover frame offset in milliseconds (`DIRECT_POST` video only).                                                                                                                                                             |
| `music_usage_confirmation` | `boolean` | Confirms the user has accepted TikTok's music-usage terms for this post. Preferred Partner API field.                                                                                                                                     |
| `user_consent`             | `boolean` | Legacy alias for `music_usage_confirmation`.                                                                                                                                                                                              |
| `is_commercial`            | `boolean` | Optional commercial content flag.                                                                                                                                                                                                         |
| `is_your_brand`            | `boolean` | Optional own-brand flag.                                                                                                                                                                                                                  |
| `is_branded_content`       | `boolean` | Optional third-party branded-content flag.                                                                                                                                                                                                |
| `auto_add_music`           | `boolean` | Optional auto-music toggle (photo posts).                                                                                                                                                                                                 |

### Pinterest Settings

Optional settings persisted from `POST /posts` / `PATCH /posts/{id}` under the
`pinterest` field. These apply only when at least one targeted account is
Pinterest.

| Field      | Type       | Description                                                                                                                                                                    |
| ---------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `board_id` | `string`   | Optional Pinterest board ID (max 128 chars).                                                                                                                                   |
| `title`    | `string`   | Optional pin title override (max 100 chars).                                                                                                                                   |
| `link`     | `string`   | Optional destination URL attached to the pin (max 2,048 chars).                                                                                                                |
| `tags`     | `string[]` | Optional topic tags (up to 30, spaces allowed). Genviral appends these to the final Pinterest description, which still must fit Pinterest's 800-character description ceiling. |

### Account States

Each post stores a normalized state for every targeted account (from `social_post_accounts`):

| Field               | Type             | Description                                                                                                       |
| ------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| `account_id`        | `string`         | ID from `GET /accounts`.                                                                                          |
| `status`            | `string`         | One of `draft`, `pending`, `scheduled`, `retry`, `posted`, `failed`, `partial`, `canceled`, `deleted`, `expired`. |
| `published_at`      | `string \| null` | Timestamp of successful publish.                                                                                  |
| `published_url`     | `string \| null` | Platform URL when the provider shares one (hosted creators).                                                      |
| `error_message`     | `string \| null` | Last error returned by the platform.                                                                              |
| `last_attempted_at` | `string \| null` | When the scheduler last touched this account.                                                                     |

```json theme={null}
{
  "accounts": {
    "total": 2,
    "states": [
      {
        "account_id": "0f4f54d4-8cce-4fb7-8c7b-befbcb8af812",
        "status": "scheduled",
        "published_at": null,
        "published_url": null,
        "error_message": null,
        "last_attempted_at": null
      },
      {
        "account_id": "6b0c8c9c-55ac-4fcb-85ec-70b5a8b0d089",
        "status": "scheduled",
        "published_at": null,
        "published_url": null,
        "error_message": null,
        "last_attempted_at": null
      }
    ]
  }
}
```

## Folder

Returned by folder endpoints under `/api/partner/v1/folders*`.

| Field              | Type             | Description                                          |
| ------------------ | ---------------- | ---------------------------------------------------- |
| `id`               | `string (UUID)`  | Folder ID.                                           |
| `name`             | `string`         | Folder display name.                                 |
| `media_type`       | `string`         | `ai_image`, `ai_video`, `upload`, or `slideshow`.    |
| `parent_folder_id` | `string \| null` | Parent folder ID (`null` for root).                  |
| `path`             | `string`         | Materialized folder path.                            |
| `file_count`       | `number`         | Count of direct items in the folder.                 |
| `subfolder_count`  | `number`         | Count of direct child folders.                       |
| `preview_files`    | `array`          | Up to 4 preview items (`id`, `url`, `content_type`). |
| `created_at`       | `string`         | Creation timestamp.                                  |
| `updated_at`       | `string`         | Last update timestamp.                               |

```json theme={null}
{
  "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
  "name": "March Campaign",
  "media_type": "upload",
  "parent_folder_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
  "path": "/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
  "file_count": 8,
  "subfolder_count": 1,
  "preview_files": [
    {
      "id": "11111111-1111-1111-1111-111111111111",
      "url": "https://cdn.vireel.io/partner-api/workspaces/workspace_123/asset-1.jpg",
      "content_type": "image/jpeg"
    }
  ],
  "created_at": "2026-03-01T09:00:00Z",
  "updated_at": "2026-03-01T09:10:00Z"
}
```

## Stats Snapshot

Analytics endpoints (and UI exports) reuse the same structures outlined in `other/docs/product/integrations/ugcinc/data-structures/account-stat.md` and `post-stat.md`.

| Field                      | Type             | Description                                     |
| -------------------------- | ---------------- | ----------------------------------------------- |
| `account_stats.id`         | `string`         | Unique stat row.                                |
| `account_stats.account_id` | `string`         | Links back to the account in current key scope. |
| `account_stats.followers`  | `number \| null` | Followers at the time of capture.               |
| `account_stats.views`      | `number \| null` | Aggregated views across all posts.              |
| `post_stats.id`            | `string`         | Unique per-post stat row.                       |
| `post_stats.post_id`       | `string`         | Links to the Genviral post.                     |
| `post_stats.views`         | `number \| null` | Views for the specific post.                    |
| `post_stats.likes`         | `number \| null` | Likes for the specific post.                    |
| `created_at`               | `string`         | Snapshot timestamp.                             |

```json theme={null}
{
  "account_stats": {
    "id": "acc_stat_1",
    "account_id": "6b0c8c9c-55ac-4fcb-85ec-70b5a8b0d089",
    "followers": 15420,
    "views": 1250000,
    "likes": 89500,
    "created_at": "2025-01-19T10:00:00Z"
  },
  "post_stats": {
    "id": "post_stat_1",
    "post_id": "11111111-1111-1111-1111-111111111111",
    "views": 48200,
    "likes": 3200,
    "created_at": "2025-01-21T04:00:00Z"
  }
}
```

## Analytics Summary

Returned by `GET /api/partner/v1/analytics/summary`.

| Field                 | Type       | Description                                                        |
| --------------------- | ---------- | ------------------------------------------------------------------ |
| `range.start`         | `string`   | Start date (`YYYY-MM-DD`) of selected range.                       |
| `range.end`           | `string`   | End date (`YYYY-MM-DD`) of selected range.                         |
| `filters.platforms`   | `string[]` | Applied platform filters.                                          |
| `filters.accountIds`  | `string[]` | Applied analytics target ID filters.                               |
| `kpis.<metric>.value` | `number`   | Current-period value for metric.                                   |
| `kpis.<metric>.delta` | `number`   | Difference from previous equivalent period.                        |
| `interactionSeries[]` | `object[]` | Daily interactions (`views`, `likes`, `comments`, `shares`).       |
| `engagementSeries[]`  | `object[]` | Daily engagement-rate values.                                      |
| `postingHeatmap[]`    | `object[]` | Daily post counts for heatmap rendering.                           |
| `postingStreak`       | `number`   | Consecutive posting-day streak ending at selected `range.end`.     |
| `contentMix[]`        | `object[]` | Post distribution by platform (`platform`, `posts`, `percentage`). |

## Analytics Target

Returned by `GET /api/partner/v1/analytics/targets` and target-management
endpoints.

| Field                    | Type             | Description                                                              |
| ------------------------ | ---------------- | ------------------------------------------------------------------------ |
| `id`                     | `string (UUID)`  | Canonical analytics target identifier used across analytics endpoints.   |
| `target_id`              | `string (UUID)`  | Legacy alias currently included in list rows for backward compatibility. |
| `platform`               | `string`         | `tiktok`, `instagram`, or `youtube`.                                     |
| `identifier`             | `string`         | Original account handle/input.                                           |
| `normalized_identifier`  | `string`         | Normalized identifier used for dedupe.                                   |
| `display_name`           | `string \| null` | Optional display label.                                                  |
| `last_refreshed_at`      | `string \| null` | Last successful refresh timestamp.                                       |
| `last_snapshot_totals`   | `object \| null` | Latest aggregate totals from snapshot.                                   |
| `last_refresh_status`    | `string \| null` | Status from latest refresh row.                                          |
| `last_refresh_error`     | `string \| null` | Latest refresh error text when failed.                                   |
| `free_refresh_available` | `boolean`        | Whether free daily refresh is currently available.                       |

## Analytics Refresh

Returned by `POST /api/partner/v1/analytics/targets/{id}/refresh` and
`GET /api/partner/v1/analytics/refreshes/{id}`.

| Field               | Type             | Description                                        |
| ------------------- | ---------------- | -------------------------------------------------- |
| `id`                | `string (UUID)`  | Refresh ID.                                        |
| `target_id`         | `string (UUID)`  | Target this refresh belongs to.                    |
| `workspace_id`      | `string \| null` | Workspace scope for billing/context.               |
| `status`            | `string`         | `pending`, `processing`, `completed`, or `failed`. |
| `credits_used`      | `number`         | Credits consumed for this refresh (0 if free).     |
| `free_refresh_used` | `boolean`        | Whether free refresh window was used.              |
| `started_at`        | `string`         | Start timestamp.                                   |
| `completed_at`      | `string \| null` | Completion timestamp when done.                    |
| `error`             | `string \| null` | Failure reason when status is `failed`.            |

<Tip>
  When available, `GET /api/partner/v1/analytics/summary/posts` returns both `analyticsId`,
  `genviralPostId`, and `externalId`. Use `genviralPostId` or `externalId` as the preferred
  correlation fields for mapping analytics rows back to the originating Partner API post.
  `analyticsId` and legacy `id` are the analytics-dataset row ID, not the post-creation ID.
</Tip>
