Connect's own legal identity, and the grievance channel India's DPDP Act 2023 requires its operator to publish.

One endpoint, no workspace, and the same answer for every application on the platform.

### Why this is not a config value

Your application is a **Data Processor** on the notice the platform operator publishes as **Data Fiduciary**. The grievance officer your privacy page names, and the one your consent capture points a user at, is therefore theirs rather than a second one of your own.

The obvious way to ship that is four lines in your `.env`:

```bash
# Don't. This is the shape this endpoint exists to replace.
APP_DATA_FIDUCIARY_NAME="..."
APP_GRIEVANCE_OFFICER_EMAIL="..."
```

An officer resigns, an address changes, and every application that copied the old one is now publishing a redressal channel that reaches nobody - silently, and for as long as it takes someone to notice. A statutory contact is the one piece of configuration that must not be able to go stale on its own, so it is read rather than copied.

### Reading it

```ts
const { companyProfile } = await connect.platform.getCompanyProfile();

companyProfile.legalName;              // the Data Fiduciary to name
companyProfile.grievance.officerEmail; // where a complaint goes
companyProfile.grievance.responseDays; // the window the notice commits to
```

Every field is resolved server-side against the platform's published defaults, so only `website` and `gstNumber` are nullable. There is nothing here for you to write a fallback for - which is the point, since a fallback is the stale copy again under another name.

### Rendering it

The SDK ships the notice as a component, so the wording stays consistent across applications:

```tsx
import { ConnectGrievanceNotice } from "@cosmoops/connect-sdk/client";

<ConnectGrievanceNotice />
```

### Caching

This changes about never, and the response carries `s-maxage=3600, stale-while-revalidate=86400`. Cache it for a day in your own layer too if you render it on a hot path. Do not cache it for a release cycle - an hour is the deliberate ceiling on how long a corrected grievance contact can stay wrong.

## Endpoints

### GET `/api/v1/application/company-profile`

Read the platform's legal identity and grievance channel

**Scope** `company:read` &nbsp;·&nbsp; **Rate limit** 60 requests / min per key

The registered entity operating Connect, and the grievance officer s.13 of India's **DPDP Act 2023** requires a Data Fiduciary to publish. Your application runs on that notice as a Data Processor, so the channel your privacy page and consent capture print is this one - not a second one of your own.

The whole reason this is an endpoint rather than four lines in your `.env` is that a statutory contact must not go stale. An officer changes, an address changes, and every application that copied the old one is now publishing a channel nobody reads. Read it from here and that cannot happen.

#### Implementation

**1. Prerequisite** - an API key scoped to `company:read`.

**2. Send the request:**
```bash
curl "https://connect.cosmoops.com/api/v1/application/company-profile" \
  -H "Authorization: Bearer YOUR_API_KEY_PLAINTEXT"
```

**3. Print it.** The identity and the whole grievance block are non-nullable, so there is nothing here for you to write a fallback for. Only `website`, `gstNumber` and `legalJurisdiction` are nullable, and those are genuinely optional facts rather than unconfigured ones - omit the line when they are `null` rather than substituting something.

`legalJurisdiction` is the seat a governing-law clause names, and is **not** the registered address: an entity registered in one state routinely names another as the venue for disputes. Reaching for `registeredAddress` instead is a specific mistake two applications made, differently.

This changes about never. Cache it for a day; the response already carries `s-maxage=3600, stale-while-revalidate=86400`. The SDK's `connect.platform.getCompanyProfile()` and the `<ConnectGrievanceNotice />` component do this for you.

#### Errors
`forbidden` (403 - key missing `company:read`), `rate_limited` (429), `unavailable` (503).

**`unavailable` means the platform operator has not filled in their company details yet**, not that you did anything wrong - there is no partial answer to give, because this endpoint exists precisely so that nobody has to invent one. Treat it the way you would a transient outage: render your page without the block rather than falling back to a copy of your own. A copy kept "just for outages" is still a copy that goes stale.

**Responses**

| Status | Meaning |
| --- | --- |
| `200` | Platform legal identity and grievance channel |
| `403` | forbidden - key missing company:read |
| `429` | rate_limited |
| `503` | unavailable - the platform company profile is not configured |

**Response body**

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `companyProfile` | `object` | yes |  |