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

# Connections Endpoint

> A single endpoint to fetch all user connections (Google Ads accounts and Google Business Profile locations) grouped by company

<Note>
  Ця сторінка також доступна [українською](/guides/connections-endpoint-uk).
</Note>

## Overview

The new **Connections endpoint** provides a single API call to retrieve all of
a user's connected services — Google Ads accounts and Google Business Profile
(GBP) locations — grouped by company.

**Before:** the frontend had to call separate endpoints for Google Ads customers
and GBP locations, often repeating requests per company (N+1 problem).

**After:** one `GET /api/v1/companies/me/connections` call returns everything.

***

## Endpoints

| Endpoint                                            | Returns                        | Use case                                                                 |
| --------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------ |
| `GET /api/v1/companies/me/connections`              | `list[CompanyWithConnections]` | Dashboard / sidebar — fetch all connections across all companies at once |
| `GET /api/v1/companies/me/{company_id}/connections` | `CompanyWithConnections`       | Company detail page — fetch connections for a specific company           |

Both require a valid `Authorization: Bearer <token>` header.

***

## Response format

Both endpoints return the same shape — a company object with two connection
arrays. The "all connections" endpoint wraps it in a list.

### `CompanyWithConnections`

<ResponseField name="id" type="integer" required>
  The company ID.
</ResponseField>

<ResponseField name="name" type="string" required>
  The company name.
</ResponseField>

<ResponseField name="date_added" type="string (ISO 8601)" required>
  When the company was created.
</ResponseField>

<ResponseField name="date_updated" type="string (ISO 8601)" required>
  When the company was last updated.
</ResponseField>

<ResponseField name="google_ads_customers" type="GoogleAdsCustomer[]" required>
  Connected Google Ads accounts. Empty array if none.

  <Expandable title="GoogleAdsCustomer fields">
    <ResponseField name="id" type="integer" required>Customer ID.</ResponseField>
    <ResponseField name="descriptive_name" type="string" required>Human-readable account name.</ResponseField>
    <ResponseField name="currency_code" type="string" required>E.g. `"USD"`, `"UAH"`.</ResponseField>
    <ResponseField name="time_zone" type="string" required>E.g. `"America/New_York"`.</ResponseField>
    <ResponseField name="status" type="string" required>E.g. `"ENABLED"`.</ResponseField>
    <ResponseField name="manager" type="boolean" required>Whether this is a manager (MCC) account.</ResponseField>
    <ResponseField name="date_added" type="string (ISO 8601)" required>When linked.</ResponseField>
    <ResponseField name="date_updated" type="string (ISO 8601)" required>Last update.</ResponseField>
    <ResponseField name="is_active" type="boolean">Always `true` in this response.</ResponseField>
    <ResponseField name="is_deleted" type="boolean">Always `false` in this response.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="google_business_locations" type="GoogleBusinessLocation[]" required>
  Connected GBP locations. Empty array if none.

  <Expandable title="GoogleBusinessLocation fields">
    <ResponseField name="id" type="string" required>Google identifier for this location.</ResponseField>
    <ResponseField name="title" type="string" required>Location name (e.g. business name).</ResponseField>
    <ResponseField name="store_code" type="string | null">External identifier for the location.</ResponseField>
    <ResponseField name="maps_uri" type="string | null">Link to the location on Google Maps.</ResponseField>

    <ResponseField name="storefront_address" type="object | null">
      Physical address of the storefront.

      <Expandable title="Address fields">
        <ResponseField name="region_code" type="string | null">CLDR region code (e.g. `"UA"`, `"US"`).</ResponseField>
        <ResponseField name="language_code" type="string | null">BCP-47 language code.</ResponseField>
        <ResponseField name="postal_code" type="string | null">Postal code.</ResponseField>
        <ResponseField name="administrative_area" type="string | null">State / province / oblast.</ResponseField>
        <ResponseField name="locality" type="string | null">City / town.</ResponseField>
        <ResponseField name="sublocality" type="string | null">Neighborhood / district.</ResponseField>
        <ResponseField name="address_lines" type="string[]">Street-level address lines.</ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

***

## Example request and response

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.cattix.com/api/v1/companies/me/connections" \
    -H "Authorization: Bearer YOUR_TOKEN"
  ```

  ```python Python (httpx) theme={null}
  import httpx

  response = httpx.get(
      "https://api.cattix.com/api/v1/companies/me/connections",
      headers={"Authorization": "Bearer YOUR_TOKEN"},
  )
  data = response.json()
  ```
</CodeGroup>

**Response** (`200 OK`):

```json theme={null}
[
  {
    "id": 1,
    "name": "My Agency",
    "date_added": "2025-06-15T10:30:00",
    "date_updated": "2025-12-01T14:22:00",
    "google_ads_customers": [
      {
        "id": 1234567890,
        "descriptive_name": "Client Store",
        "currency_code": "USD",
        "time_zone": "America/New_York",
        "status": "ENABLED",
        "manager": false,
        "date_added": "2025-07-01T09:00:00",
        "date_updated": "2025-11-20T08:15:00",
        "is_active": true,
        "is_deleted": false
      }
    ],
    "google_business_locations": [
      {
        "id": "locations/abc123",
        "title": "Client Store — Downtown",
        "store_code": "STORE-001",
        "maps_uri": "https://maps.google.com/?cid=123456",
        "storefront_address": {
          "region_code": "US",
          "language_code": "en",
          "postal_code": "10001",
          "administrative_area": "NY",
          "locality": "New York",
          "sublocality": null,
          "address_lines": ["123 Main St"]
        }
      }
    ]
  },
  {
    "id": 2,
    "name": "Side Project",
    "date_added": "2025-09-10T12:00:00",
    "date_updated": "2025-09-10T12:00:00",
    "google_ads_customers": [],
    "google_business_locations": []
  }
]
```

<Tip>
  Companies with no connections still appear in the response — their
  `google_ads_customers` and `google_business_locations` arrays are empty.
  This lets you show "No connections yet" UI without extra logic.
</Tip>

***

## Single-company endpoint

To fetch connections for a specific company, use the company ID in the path:

```bash theme={null}
curl -X GET "https://api.cattix.com/api/v1/companies/me/42/connections" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Returns a **single object** (not an array):

```json theme={null}
{
  "id": 42,
  "name": "My Agency",
  "date_added": "2025-06-15T10:30:00",
  "date_updated": "2025-12-01T14:22:00",
  "google_ads_customers": [ ... ],
  "google_business_locations": [ ... ]
}
```

***

## What gets filtered out

The backend automatically excludes inactive or deleted resources. You **do not**
need to filter on the frontend side. The following are excluded:

| Excluded when…                        | Example                          |
| ------------------------------------- | -------------------------------- |
| Company is soft-deleted               | Company was removed by admin     |
| User membership is inactive           | User was removed from a company  |
| Connection link is inactive           | Google Ads account was unlinked  |
| Resource itself is inactive / deleted | Google Ads account was suspended |

***

## Caching

Responses are cached on the backend (Redis). You do **not** need to implement
any caching logic on the frontend.

The cache is automatically invalidated when:

* A company is created, updated, or deleted
* A member is added to or removed from a company
* A Google Ads account or GBP location is linked / unlinked

This means calling the endpoint after any mutation will return fresh data.

***

## Migration guide

If you are currently fetching Google Ads customers and GBP locations from
separate endpoints:

<Steps>
  <Step title="Replace multiple calls with one">
    Replace individual calls to Google Ads and GBP endpoints with a single call
    to `GET /api/v1/companies/me/connections`.
  </Step>

  <Step title="Update your data model">
    The response groups connections under each company. Map your UI state
    accordingly:

    ```typescript theme={null}
    interface CompanyWithConnections {
      id: number;
      name: string;
      date_added: string;
      date_updated: string;
      google_ads_customers: GoogleAdsCustomer[];
      google_business_locations: GoogleBusinessLocation[];
    }

    // The "all connections" endpoint returns:
    type AllConnections = CompanyWithConnections[];
    ```
  </Step>

  <Step title="Remove client-side filtering">
    The backend already filters out inactive / deleted resources. Remove any
    frontend `is_active` / `is_deleted` checks.
  </Step>

  <Step title="Remove client-side caching (optional)">
    If you had client-side caching for connection data, it can be simplified or
    removed since the backend now caches the response.
  </Step>
</Steps>
