# Partner

> Part of the Cowliss docs. Markdown for every page: append `index.md` to its URL. Site map: /llms.txt

<!-- GENERATED by apps/docs/scripts/generate-api-reference.ts. Do not edit. Regenerate with `pnpm -F cowliss-docs generate`. -->

A partner is a business that sells Cowliss inside its own product, one organization per customer, and the customer never signs in. These routes take a partner key (`Authorization: Bearer cpk_...`), issued by arrangement, and accept nothing else; every other route refuses a partner key. `create` returns an `org:admin` pipeline key once, and from then on the partner talks to that organization with it on the ordinary routes (apps, sources, keys, sending domains, automations, broadcasts, the billing summary): in an organization a partner created, that key acts as `org:admin` everywhere a signed-in admin would, because nobody can sign in. An organization the partner did not create is a **404** on every route here. Plan, overage, suspension and purge are the partner's to call in whatever order its own lifecycle needs; Cowliss enforces none of that ordering. See the [Partners guide](/guides/partners/).

## POST /v1/partner/orgs

Create an organization for a customer

Creates the organization with nobody in it, records the partner on it, and mints one `org:admin` pipeline key for it. The key is in this response and nowhere else; store it. A second create with the same `externalId` is allowed: the partner decides what one customer maps to.

**Auth:** Session token.

**Request body**

```json
{
  "data": {
    "name": "string",
    "slug": "string",
    "externalId": "string"
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.name` | string | yes | length 1–100 |
| `data.slug` | string | no | length 1–100 |
| `data.externalId` | string | no | length 1–200 |

**Response 201**

```json
{
  "data": {
    "orgId": "string",
    "slug": "string",
    "pipelineKey": "string"
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.orgId` | string | yes |  |
| `data.slug` | string | yes |  |
| `data.pipelineKey` | string | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## GET /v1/partner/orgs/{id}

Read an organization the partner created

**Auth:** Session token.

**Response 200**

```json
{
  "data": {
    "orgId": "string",
    "slug": "string",
    "name": "string",
    "externalId": "string",
    "plan": "free",
    "overageAllowed": true,
    "status": "active",
    "createdAt": "2026-01-15T09:30:00.000Z"
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.orgId` | string | yes |  |
| `data.slug` | string \| null | yes |  |
| `data.name` | string \| null | yes |  |
| `data.externalId` | string \| null | yes |  |
| `data.plan` | "free" \| "plus" | yes |  |
| `data.overageAllowed` | boolean | yes |  |
| `data.status` | "active" \| "suspended" | yes |  |
| `data.createdAt` | string (date-time) | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## PUT /v1/partner/orgs/{id}/plan

Set the organization's plan and whether overage is allowed

The plan set here wins over any subscription. With `overageAllowed`, usage past the included amount is counted (see `overageMicros` on the billing summary) and never refused, for the partner to bill through its own channel. Included usage, app and sending-domain limits per plan are unchanged.

**Auth:** Session token.

**Request body**

```json
{
  "data": {
    "plan": "free",
    "overageAllowed": true
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.plan` | "free" \| "plus" | yes |  |
| `data.overageAllowed` | boolean | yes |  |

**Response 200**

```json
{
  "data": {
    "orgId": "string",
    "slug": "string",
    "name": "string",
    "externalId": "string",
    "plan": "free",
    "overageAllowed": true,
    "status": "active",
    "createdAt": "2026-01-15T09:30:00.000Z"
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.orgId` | string | yes |  |
| `data.slug` | string \| null | yes |  |
| `data.name` | string \| null | yes |  |
| `data.externalId` | string \| null | yes |  |
| `data.plan` | "free" \| "plus" | yes |  |
| `data.overageAllowed` | boolean | yes |  |
| `data.status` | "active" \| "suspended" | yes |  |
| `data.createdAt` | string (date-time) | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## POST /v1/partner/orgs/{id}/suspend

Suspend the organization

Ingestion refuses, no automation starts a run (runs in flight finish with their sends skipped), nothing is sent, and no broadcast can be scheduled. Data is kept. Already suspended is a no-op.

**Auth:** Session token.

**Response 200**

```json
{
  "data": {
    "orgId": "string",
    "slug": "string",
    "name": "string",
    "externalId": "string",
    "plan": "free",
    "overageAllowed": true,
    "status": "active",
    "createdAt": "2026-01-15T09:30:00.000Z"
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.orgId` | string | yes |  |
| `data.slug` | string \| null | yes |  |
| `data.name` | string \| null | yes |  |
| `data.externalId` | string \| null | yes |  |
| `data.plan` | "free" \| "plus" | yes |  |
| `data.overageAllowed` | boolean | yes |  |
| `data.status` | "active" \| "suspended" | yes |  |
| `data.createdAt` | string (date-time) | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## POST /v1/partner/orgs/{id}/restore

Restore a suspended organization

Clears the suspension; automations that are on trigger again. Not suspended is a no-op.

**Auth:** Session token.

**Response 200**

```json
{
  "data": {
    "orgId": "string",
    "slug": "string",
    "name": "string",
    "externalId": "string",
    "plan": "free",
    "overageAllowed": true,
    "status": "active",
    "createdAt": "2026-01-15T09:30:00.000Z"
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.orgId` | string | yes |  |
| `data.slug` | string \| null | yes |  |
| `data.name` | string \| null | yes |  |
| `data.externalId` | string \| null | yes |  |
| `data.plan` | "free" \| "plus" | yes |  |
| `data.overageAllowed` | boolean | yes |  |
| `data.status` | "active" \| "suspended" | yes |  |
| `data.createdAt` | string (date-time) | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## DELETE /v1/partner/orgs/{id}

Delete the organization and everything in it

Starts the purge and returns at once: every run is cancelled, every row and event removed, sending domains released, keys revoked, and the organization itself deleted last. Irreversible. A second call while it runs, or after it finished, answers the same.

**Auth:** Session token.

**Response 202**

```json
{
  "data": {
    "workflowId": "string"
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.workflowId` | string | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).
