# Invitation Templates

## List invitation templates

**get** `/v1/invitation_templates`

Lists your invitation templates, newest-first, one page at a time.
An empty list on a fresh brand means none created yet; create one and
send; if creation is refused `403 invitation_card_not_granted`, your
brand is not yet approved for invitations of that shape: approval is
per-brand, raised with us, not self-service.

### Query Parameters

- `cursor: optional string`

  The previous page's `next_cursor`, verbatim; absent starts from the first page. Not a cursor this API issued returns HTTP 400 `code` 1013.

- `limit: optional number`

  Page size; absent (or non-numeric) reads as 25, above 100 reads as 100.

### Returns

- `data: array of object { id, created_at, has_logo, 3 more }`

  - `id: string`

    The template id (`invt_…`); what a send's `template_id` references.

  - `created_at: string`

  - `has_logo: boolean`

    Whether a logo is stored. A template with a logo renders the image card; one without renders the plain card.

  - `name: string`

    The brand name printed on the invitation card.

  - `updated_at: string`

  - `version: number`

    Edit counter that only ever counts up, also returned as this resource's
    strong `ETag`. Echo it in `If-Match` on the next `PUT`; a stale one is
    refused `412` rather than overwriting someone else's edit.

- `next_cursor: string`

  Pass back as `?cursor=` for the next page. EMPTY when this page exhausted the list, that, not an empty `data`, is how paging ends.

### Example

```http
curl https://messages.api.linqapp.com/v1/invitation_templates \
    -H "Authorization: Bearer $LINQ_AMB_API_KEY"
```

#### Response

```json
{
  "data": [
    {
      "id": "invt_a4f2c718d0",
      "name": "Acme Rides",
      "has_logo": true,
      "version": 3,
      "created_at": "2026-08-10T09:00:00Z",
      "updated_at": "2026-08-12T15:30:00Z"
    }
  ],
  "next_cursor": ""
}
```

## Create an invitation template

**post** `/v1/invitation_templates`

Creates an invitation template: the name (and optionally the logo file)
that fill the card, saved once, referenced by id on every send. The
response's `ETag` carries the version `PUT` will want in `If-Match`.

**Errors**

- HTTP 403 `code` 2029: your brand is not approved
  for invitations of this shape (with/without a logo); raised with us,
  not self-service.
- HTTP 422: field-level validation (`name_required`, `too_long`,
  `brand_logo_not_png`, `logo_too_large`).
- HTTP 413 `code` 1073: the whole request body exceeds the ceiling:
  the logo may be at most 143,360 bytes raw.

### Returns

- `id: string`

  The template id (`invt_…`); what a send's `template_id` references.

- `created_at: string`

- `has_logo: boolean`

  Whether a logo is stored. A template with a logo renders the image card; one without renders the plain card.

- `name: string`

  The brand name printed on the invitation card.

- `updated_at: string`

- `version: number`

  Edit counter that only ever counts up, also returned as this resource's
  strong `ETag`. Echo it in `If-Match` on the next `PUT`; a stale one is
  refused `412` rather than overwriting someone else's edit.

### Example

```http
curl https://messages.api.linqapp.com/v1/invitation_templates \
    -H 'Content-Type: multipart/form-data' \
    -H "Authorization: Bearer $LINQ_AMB_API_KEY" \
    -F name=name
```

#### Response

```json
{
  "id": "invt_a4f2c718d0",
  "name": "Acme Rides",
  "has_logo": true,
  "version": 1,
  "created_at": "2026-08-10T09:00:00Z",
  "updated_at": "2026-08-10T09:00:00Z"
}
```

## Get an invitation template

**get** `/v1/invitation_templates/{invt}`

Fetch one template. Unknown ids, and another brand's; return HTTP 404.

### Path Parameters

- `invt: string`

### Returns

- `id: string`

  The template id (`invt_…`); what a send's `template_id` references.

- `created_at: string`

- `has_logo: boolean`

  Whether a logo is stored. A template with a logo renders the image card; one without renders the plain card.

- `name: string`

  The brand name printed on the invitation card.

- `updated_at: string`

- `version: number`

  Edit counter that only ever counts up, also returned as this resource's
  strong `ETag`. Echo it in `If-Match` on the next `PUT`; a stale one is
  refused `412` rather than overwriting someone else's edit.

### Example

```http
curl https://messages.api.linqapp.com/v1/invitation_templates/$INVT \
    -H "Authorization: Bearer $LINQ_AMB_API_KEY"
```

#### Response

```json
{
  "id": "invt_a4f2c718d0",
  "name": "Acme Rides",
  "has_logo": true,
  "version": 3,
  "created_at": "2026-08-10T09:00:00Z",
  "updated_at": "2026-08-12T15:30:00Z"
}
```

## Download an invitation template's logo

**get** `/v1/invitation_templates/{invt}/logo`

Downloads a template's stored logo, verbatim, under its stored MIME type
(`image/png`: the logo is checked to be a PNG when it is saved). This is
the image the card carries when the template has one; `has_logo` on the
template says whether there is one to fetch.

**Errors**

- HTTP 404 `code` 2056: the template is yours and carries no logo.
- HTTP 404 `code` 2033: unknown ids, and another
  brand's, exactly as the template read answers them.

### Path Parameters

- `invt: string`

### Example

```http
curl https://messages.api.linqapp.com/v1/invitation_templates/$INVT/logo \
    -H "Authorization: Bearer $LINQ_AMB_API_KEY"
```

## Update an invitation template

**put** `/v1/invitation_templates/{invt}`

Replaces a template: a full replacement, never a patch, under the
`If-Match` contract: missing → `428`, stale → `412` naming the current
version. The logo is three-valued: an absent
`logo` part KEEPS the stored logo, a present one replaces it, and
`remove_logo=true` clears it. A change that flips the template between
with-logo and without is re-checked against your brand's approval and
refused `403 invitation_card_not_granted` at the edit rather than
discovered at the next send. Size refusals match the create:
`422 logo_too_large` for the logo, `413 too_large` past the whole-body
ceiling.

### Path Parameters

- `invt: string`

### Header Parameters

- `"If-Match": string`

### Returns

- `id: string`

  The template id (`invt_…`); what a send's `template_id` references.

- `created_at: string`

- `has_logo: boolean`

  Whether a logo is stored. A template with a logo renders the image card; one without renders the plain card.

- `name: string`

  The brand name printed on the invitation card.

- `updated_at: string`

- `version: number`

  Edit counter that only ever counts up, also returned as this resource's
  strong `ETag`. Echo it in `If-Match` on the next `PUT`; a stale one is
  refused `412` rather than overwriting someone else's edit.

### Example

```http
curl https://messages.api.linqapp.com/v1/invitation_templates/$INVT \
    -X PUT \
    -H 'Content-Type: multipart/form-data' \
    -H "Authorization: Bearer $LINQ_AMB_API_KEY" \
    -F name=name
```

#### Response

```json
{
  "id": "invt_a4f2c718d0",
  "name": "Acme Rides Support",
  "has_logo": true,
  "version": 4,
  "created_at": "2026-08-10T09:00:00Z",
  "updated_at": "2026-08-12T16:00:00Z"
}
```

## Delete an invitation template

**delete** `/v1/invitation_templates/{invt}`

Deletes a template. Invitations already sent from it are unaffected;
what went out is recorded on each invitation. No precondition: deletion
is terminal, and a delete-vs-edit race resolves visibly either way.

### Path Parameters

- `invt: string`

### Returns

- `ok: true`

  - `true`

### Example

```http
curl https://messages.api.linqapp.com/v1/invitation_templates/$INVT \
    -X DELETE \
    -H "Authorization: Bearer $LINQ_AMB_API_KEY"
```

#### Response

```json
{
  "ok": true
}
```

## Domain Types

### Invitation Template List Response

- `InvitationTemplateListResponse object { data, next_cursor }`

  One page of your invitation templates, newest-first.

  - `data: array of object { id, created_at, has_logo, 3 more }`

    - `id: string`

      The template id (`invt_…`); what a send's `template_id` references.

    - `created_at: string`

    - `has_logo: boolean`

      Whether a logo is stored. A template with a logo renders the image card; one without renders the plain card.

    - `name: string`

      The brand name printed on the invitation card.

    - `updated_at: string`

    - `version: number`

      Edit counter that only ever counts up, also returned as this resource's
      strong `ETag`. Echo it in `If-Match` on the next `PUT`; a stale one is
      refused `412` rather than overwriting someone else's edit.

  - `next_cursor: string`

    Pass back as `?cursor=` for the next page. EMPTY when this page exhausted the list, that, not an empty `data`, is how paging ends.

### Invitation Template Create Response

- `InvitationTemplateCreateResponse object { id, created_at, has_logo, 3 more }`

  One of YOUR invitation templates: the brand name and optional logo that
  fill the card, saved once under an id we mint, referenced on every send.
  You never see or supply Apple's internal card identifiers: the platform
  picks the right card from whether the template carries a logo.

  - `id: string`

    The template id (`invt_…`); what a send's `template_id` references.

  - `created_at: string`

  - `has_logo: boolean`

    Whether a logo is stored. A template with a logo renders the image card; one without renders the plain card.

  - `name: string`

    The brand name printed on the invitation card.

  - `updated_at: string`

  - `version: number`

    Edit counter that only ever counts up, also returned as this resource's
    strong `ETag`. Echo it in `If-Match` on the next `PUT`; a stale one is
    refused `412` rather than overwriting someone else's edit.

### Invitation Template Retrieve Response

- `InvitationTemplateRetrieveResponse object { id, created_at, has_logo, 3 more }`

  One of YOUR invitation templates: the brand name and optional logo that
  fill the card, saved once under an id we mint, referenced on every send.
  You never see or supply Apple's internal card identifiers: the platform
  picks the right card from whether the template carries a logo.

  - `id: string`

    The template id (`invt_…`); what a send's `template_id` references.

  - `created_at: string`

  - `has_logo: boolean`

    Whether a logo is stored. A template with a logo renders the image card; one without renders the plain card.

  - `name: string`

    The brand name printed on the invitation card.

  - `updated_at: string`

  - `version: number`

    Edit counter that only ever counts up, also returned as this resource's
    strong `ETag`. Echo it in `If-Match` on the next `PUT`; a stale one is
    refused `412` rather than overwriting someone else's edit.

### Invitation Template Update Response

- `InvitationTemplateUpdateResponse object { id, created_at, has_logo, 3 more }`

  One of YOUR invitation templates: the brand name and optional logo that
  fill the card, saved once under an id we mint, referenced on every send.
  You never see or supply Apple's internal card identifiers: the platform
  picks the right card from whether the template carries a logo.

  - `id: string`

    The template id (`invt_…`); what a send's `template_id` references.

  - `created_at: string`

  - `has_logo: boolean`

    Whether a logo is stored. A template with a logo renders the image card; one without renders the plain card.

  - `name: string`

    The brand name printed on the invitation card.

  - `updated_at: string`

  - `version: number`

    Edit counter that only ever counts up, also returned as this resource's
    strong `ETag`. Echo it in `If-Match` on the next `PUT`; a stale one is
    refused `412` rather than overwriting someone else's edit.

### Invitation Template Delete Response

- `InvitationTemplateDeleteResponse object { ok }`

  The bare `{"ok":true}` acknowledgement; failures ride the error envelope instead.

  - `ok: true`

    - `true`
