# Google Analytics

Source: https://ceyo.ai/docs/signal/google-analytics

### Google Analytics

Connect GA4 and read referral, conversion, and landing-page analytics.

> **Package and capabilities**
>
> The assigned package must set `advanced.google_analytics_enabled` to `true`. Analytics reads require `analytics:read`; connection and configuration operations require `analytics:write`.

**Base URL:** `https://api.signal.ceyo.ai/v1`

> **Project and location scope**
>
> Use `/projects/{project_id}/analytics` for a standard project or `/projects/{project_id}/locations/{location_id}/analytics` for a location. IDs may be Signal UUIDs or partner external IDs.

**1\. Start authorization**

Call `POST /analytics/connect` at the selected scope and send the user to the returned `authorization_url`.

**2\. Complete the callback**

Google returns to Signal's public callback, which validates the API key and scope stored in state and exchanges the code.

**3\. Select a property**

List accounts and properties, then call `PUT /analytics/select_property`. To use partner-managed credentials instead, configure a token source and call `PUT /analytics/external_source`.

**4\. Sync**

Queue collection with `POST /analytics/sync`.

### Get analytics overview

`GET {scope}/analytics`

Returns the GA4 overview for a project or location.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `days` | integer | Optional; Default: 30 | Reporting window. Values are clamped to 7–90 days. |

#### Response body

`summary`:**object**`daily_series`:**object\[\]**`platforms`:**object\[\]**`conversion_summary`:**object**`action_markers`:**object\[\]**`connection`:**object**`days`:**integer**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `summary` | object |  | Traffic and conversion totals with trends. |
| `daily_series` | object\[\] |  | Daily analytics points. |
| `platforms` | object\[\] |  | AI platform breakdown. |
| `conversion_summary` | object |  | Conversion totals. |
| `action_markers` | object\[\] |  | Completed action markers in the window. |
| `connection` | object |  | Current GA4 connection summary. |
| `days` | integer |  | Applied reporting window. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Get analytics referrals

`GET {scope}/analytics/referrals`

Returns earned referral sources and their GA4 traffic.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `days` | integer | Optional; Default: 30 | Reporting window. Values are clamped to 7–90 days. |
| `page` | integer | Optional; Default: 1 | 1-based page number. Each page contains 25 records. |

#### Response body

`sources`:**object\[\]**`sources_pagination`:**Pagination**`hero`:**object**`summary`:**string | null**`days`:**integer**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `sources` | object\[\] |  | Referral sources for the requested page. |
| `sources_pagination` | Pagination |  | 25-item pagination metadata. |
| `hero` | object |  | Headline referral metrics. |
| `summary` | string \| null |  | Generated referral summary when available. |
| `days` | integer |  | Applied reporting window. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Get analytics conversions

`GET {scope}/analytics/conversions`

Returns conversion performance, optionally filtered by GA4 key event.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `days` | integer | Optional; Default: 30 | Reporting window. Values are clamped to 7–90 days. |
| `event_names` | string \| string\[\] | Optional | Comma-separated or repeated key event names. Maximum: 50. |

#### Response body

`hero`:**object**`rate_by_source`:**object\[\]**`by_platform`:**object\[\]**`summary`:**string | null**`days`:**integer**`applied_event_names`:**string\[\]**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `hero` | object |  | Headline conversion metrics. |
| `rate_by_source` | object\[\] |  | Conversion rates by source. |
| `by_platform` | object\[\] |  | Conversion metrics by channel. |
| `summary` | string \| null |  | Generated conversion summary when available. |
| `days` | integer |  | Applied reporting window. |
| `applied_event_names` | string\[\] |  | Normalized event filter. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Get analytics conversion events

`GET {scope}/analytics/conversion_events`

Lists observed GA4 key events for conversion filtering.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `days` | integer | Optional; Default: 90 | Reporting window. Values are clamped to 7–180 days. |

#### Response body

`events`:**{ name, total\_key\_events }\[\]**`days`:**integer**`limit`:**integer**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `events` | { name, total\_key\_events }\[\] |  | Up to 200 key events, ordered by count. |
| `days` | integer |  | Applied reporting window. |
| `limit` | integer |  | Maximum returned event count. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Get analytics landing pages

`GET {scope}/analytics/landing_pages`

Returns AI landing-page performance and platform distribution.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `days` | integer | Optional; Default: 30 | Reporting window. Values are clamped to 7–90 days. |
| `page` | integer | Optional; Default: 1 | 1-based page number. Each page contains 25 records. |
| `matrix_page` | integer | Optional; Default: 1 | 1-based page for the 25-item platform matrix. |

#### Response body

`pages`:**object\[\]**`pages_pagination`:**Pagination**`hero`:**object**`platform_matrix`:**object**`matrix_pagination`:**Pagination**`days`:**integer**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `pages` | object\[\] |  | Landing-page metrics. |
| `pages_pagination` | Pagination |  | Landing-page pagination. |
| `hero` | object |  | Headline landing-page metrics. |
| `platform_matrix` | object |  | Platform names, colors, and paged rows. |
| `matrix_pagination` | Pagination |  | Platform matrix pagination. |
| `days` | integer |  | Applied reporting window. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Get analytics connection

`GET {scope}/analytics/connection`

Returns the current connection for a project or location.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Response body

`project_id`:**uuid**`location_id`:**uuid**`connection`:**Connection**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | uuid |  | Resolved project ID. |
| `location_id` | uuid |  | Resolved location ID when location-scoped. |
| `connection` | Connection |  | Connection details, or disconnected status. |

#### Connection

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Connection identifier. |
| `status` | connected \| disconnected \| revoked \| error |  | Current connection status. |
| `auth_strategy` | ceyo\_oauth \| external\_token\_source |  | Credential strategy. |
| `account_id` | string \| null |  | Selected GA4 account. |
| `property_id` | string \| null |  | Selected GA4 property. |
| `last_synced_at` | datetime \| null |  | Most recent completed sync. |
| `syncing_since` | datetime \| null |  | Start time of the active sync. |
| `error_message` | string \| null |  | Most recent connection error. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Connect Google Analytics

`POST {scope}/analytics/connect`

Creates a short-lived Google OAuth authorization URL.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Response body

`authorization_url`:**URL**

Google authorization URL.

> **Callback**
>
> Google returns to `/v1/google_analytics/oauth/callback`, which completes the exchange. Poll the connection endpoint after the browser reports success.

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Exchange authorization code

`POST {scope}/analytics/exchange`

Exchanges a Google authorization code for a scoped connection.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Request body

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string | Required | Authorization code returned by Google. |
| `state` | string | Required | Unmodified state from the authorization flow. |

#### Response body

`connected`:**true**`connection_id`:**uuid**`status`:**string**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `connected` | true |  | Confirms that credentials were stored. |
| `connection_id` | uuid |  | Connection identifier. |
| `status` | string |  | Current connection status. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### List analytics accounts

`GET {scope}/analytics/accounts`

Lists Google Analytics accounts available to the connection.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Response body

`accounts`:**object\[\]**

Available GA4 account summaries.

> **Capability**
>
> This connection setup endpoint requires `analytics:write`.

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### List analytics properties

`GET {scope}/analytics/properties`

Lists GA4 properties for an available account.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `account_id` | string | Required | Google Analytics account identifier. |

#### Response body

`properties`:**object\[\]**

GA4 properties in the account.

> **Capability**
>
> This connection setup endpoint requires `analytics:write`.

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Select analytics property

`PUT {scope}/analytics/select_property`

Selects the GA4 property and queues an initial sync.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Request body

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `property_id` | string | Required | GA4 property identifier. |
| `property_name` | string | Optional | Property display name. |
| `account_id` | string | Required | Parent account identifier. |
| `account_name` | string | Optional | Parent account display name. |

#### Response body

`selected`:**true**`connection`:**Connection**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `selected` | true |  | Confirms the selection. |
| `connection` | Connection |  | Updated connection. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Set external analytics source

`PUT {scope}/analytics/external_source`

Connects a scope through a workspace token source.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Request body

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `token_source_id` | uuid | Required | Enabled workspace token source. |
| `external_resource_id` | string | Required | Resource ID sent to the partner endpoint. |
| `property_id` | string | Optional | GA4 property ID. Required before syncing. |
| `property_name` | string | Optional | GA4 property display name. |
| `account_id` | string | Optional | GA4 account ID. |
| `account_name` | string | Optional | GA4 account display name. |

#### Response body

`connected`:**true**`connection`:**Connection**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `connected` | true |  | Confirms the external connection. |
| `connection` | Connection |  | Updated connection. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Sync Google Analytics

`POST {scope}/analytics/sync`

Queues GA4 collection for the selected property.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Request body

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `force_full` | JSON boolean | Optional; Default: false | Requests a full refresh instead of an incremental sync; strings are rejected. |

#### 202 response body

`queued`:**true**

Returned with 202 Accepted.

> **Concurrency**
>
> A request made during an active sync returns `409 sync_in_progress`.

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `409` | sync\_in\_progress |  | A Google Analytics sync is already in progress. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### Disconnect Google Analytics

`DELETE {scope}/analytics/connection`

Disconnects GA4 and removes all stored analytics for the scope.

#### Project path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Location path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

> **Destructive operation**
>
> Disconnecting clears credentials, the selected property, and collected daily and event metrics.

#### Response body

`disconnected`:**true**

Confirms the connection was removed.

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden \| analytics\_unavailable |  | The key lacks access or GA4 is not enabled by the package. |
| `404` | not\_found |  | The scope or requested analytics resource was not found. |
| `422` | validation\_failed \| analytics\_not\_connected |  | Input is invalid or the connection is not ready. |
| `429` | google\_rate\_limited |  | Google Analytics temporarily rate limited the request. |
| `502` | google\_unavailable \| external\_token\_unavailable \| external\_token\_unauthorized |  | Google or an external token provider is temporarily unavailable. |

### List Google Analytics token sources

`GET /google_analytics_token_sources`

Lists external token sources in the API key workspace.

#### Response body

`token_sources`:**TokenSource\[\]**

Workspace token sources ordered by name.

#### TokenSource

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Token source identifier. |
| `name` | string |  | Workspace-unique display name. |
| `strategy` | external\_token\_endpoint |  | Credential strategy. |
| `enabled` | boolean |  | Whether new token requests are allowed. |
| `endpoint_url` | URL |  | Partner endpoint that returns a Google access token. |
| `http_method` | GET \| POST |  | HTTP method used to request a token. |
| `service_key_header` | string |  | Header used to send the service key. |
| `has_service_key` | boolean |  | Whether an encrypted service key is stored. |
| `header_names` | string\[\] |  | Configured custom header names; values are never returned. |
| `request_resource_id_key` | string |  | Request field used for the external resource identifier. |
| `attached_scope_count` | integer |  | Number of attached project or location scopes. |

> **Capability**
>
> All token source endpoints, including this list, require workspace-scoped `analytics:write`.

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden |  | The key lacks workspace analytics:write access. |
| `404` | not\_found |  | The token source was not found in this workspace. |
| `422` | validation\_failed \| limit\_reached |  | Input is invalid or the workspace limit was reached. |

### Create Google Analytics token source

`POST /google_analytics_token_sources`

Creates an external token endpoint configuration.

#### Request body

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `name` | string | Required | Workspace-unique display name. |
| `strategy` | external\_token\_endpoint | Required | Token source strategy. |
| `endpoint_url` | URL | Required | HTTPS endpoint that returns a Google access token. |
| `http_method` | GET \| POST | Required | Method used to call the endpoint. |
| `service_key_header` | string | Required | Header name for the service key. |
| `service_key` | string | Optional | Optional secret value. It is encrypted and never returned. |
| `request_resource_id_key` | string | Required | Request field for external\_resource\_id. |
| `enabled` | boolean | Required | Enables or disables the source. |
| `headers` | object | Optional | Optional request headers with scalar values. |

#### 201 response body

`token_source`:**TokenSource**

Created token source. Returns 201.

#### TokenSource

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Token source identifier. |
| `name` | string |  | Workspace-unique display name. |
| `strategy` | external\_token\_endpoint |  | Credential strategy. |
| `enabled` | boolean |  | Whether new token requests are allowed. |
| `endpoint_url` | URL |  | Partner endpoint that returns a Google access token. |
| `http_method` | GET \| POST |  | HTTP method used to request a token. |
| `service_key_header` | string |  | Header used to send the service key. |
| `has_service_key` | boolean |  | Whether an encrypted service key is stored. |
| `header_names` | string\[\] |  | Configured custom header names; values are never returned. |
| `request_resource_id_key` | string |  | Request field used for the external resource identifier. |
| `attached_scope_count` | integer |  | Number of attached project or location scopes. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden |  | The key lacks workspace analytics:write access. |
| `404` | not\_found |  | The token source was not found in this workspace. |
| `422` | validation\_failed \| limit\_reached |  | Input is invalid or the workspace limit was reached. |

### Update Google Analytics token source

`PATCH /google_analytics_token_sources/{id}`

Updates a workspace token source.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid | Required | Token source identifier. |

#### Request body

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `name` | string | Optional | Workspace-unique display name. |
| `strategy` | external\_token\_endpoint | Optional | Token source strategy. |
| `endpoint_url` | URL | Optional | HTTPS endpoint that returns a Google access token. |
| `http_method` | GET \| POST | Optional | Method used to call the endpoint. |
| `service_key_header` | string | Optional | Header name for the service key. |
| `service_key` | string | Optional | Replacement secret. Omit or send blank to keep the existing value. |
| `request_resource_id_key` | string | Optional | Request field for external\_resource\_id. |
| `enabled` | boolean | Optional | Enables or disables the source. |
| `headers` | object | Optional | Optional request headers with scalar values. |

#### Response body

`token_source`:**TokenSource**

Updated token source.

#### TokenSource

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Token source identifier. |
| `name` | string |  | Workspace-unique display name. |
| `strategy` | external\_token\_endpoint |  | Credential strategy. |
| `enabled` | boolean |  | Whether new token requests are allowed. |
| `endpoint_url` | URL |  | Partner endpoint that returns a Google access token. |
| `http_method` | GET \| POST |  | HTTP method used to request a token. |
| `service_key_header` | string |  | Header used to send the service key. |
| `has_service_key` | boolean |  | Whether an encrypted service key is stored. |
| `header_names` | string\[\] |  | Configured custom header names; values are never returned. |
| `request_resource_id_key` | string |  | Request field used for the external resource identifier. |
| `attached_scope_count` | integer |  | Number of attached project or location scopes. |

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden |  | The key lacks workspace analytics:write access. |
| `404` | not\_found |  | The token source was not found in this workspace. |
| `422` | validation\_failed \| limit\_reached |  | Input is invalid or the workspace limit was reached. |

### Delete Google Analytics token source

`DELETE /google_analytics_token_sources/{id}`

Deletes an unused workspace token source.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid | Required | Token source identifier. |

#### Response body

`deleted`:**true**

Confirms deletion.

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent or invalid. |
| `403` | forbidden |  | The key lacks workspace analytics:write access. |
| `404` | not\_found |  | The token source was not found in this workspace. |
| `409` | token\_source\_in\_use |  | Attached analytics scopes must be disconnected first. |
| `422` | validation\_failed \| limit\_reached |  | Input is invalid or the workspace limit was reached. |
