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

# Send a contact card

> POST /api/v1/chats/:id/send-contact — send a structured vCard as a tappable contact bubble.

<Note>
  **Auth.** HMAC v1 or bearer token — see [Authentication](/api/authentication).
  **Status.** Live · **Idempotent:** No.
</Note>

Builds a vCard from the supplied fields and sends it as a tappable contact bubble in the chat. The recipient sees a normal contact card they can tap to save. Works in both DMs and groups.

Wrap the card details in a top-level `contact` object (or supply raw `vcard_text`). Include at least one identifying field inside `contact` — `full_name`, `given_name`, `family_name`, `organization`, or a non-empty `phones` / `emails`.

This is independent of the line's own saved contact card — use [`share-contact-info`](/api/contact-sharing/share-info) to share the line's "Me" card.

## Addressing the recipient

Pick the form that matches your state:

1. **By chat id** — `POST /api/v1/chats/{id}/send-contact` once a chat exists.
2. **By phone** — pass `to` in the request body. Use this on first-touch when no chat exists yet; Chert resolves or creates the chat in-line.

```jsonc theme={null}
{
  "to": "+14155551234",                  // <- E.164 phone (alternative to {id} in the URL)
  "contact": {
    "full_name": "Sean Franklin",
    "given_name": "Sean",
    "family_name": "Franklin",
    "organization": "Acme Inc",
    "phones": [{ "value": "+14155551234", "label": "mobile" }],
    "emails": [{ "value": "sean@acme.example", "label": "work" }]
  }
}
```

## Request

`POST /api/v1/chats/{id}/send-contact`

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://console.trychert.com/api/v1/chats/ch_01H.../send-contact \
    -H "x-chert-tenant: $TENANT" \
    -H "x-chert-signature: v1,$TS,$SIG" \
    -H "content-type: application/json" \
    -d '{
      "contact": {
        "full_name": "Sean Franklin",
        "given_name": "Sean",
        "family_name": "Franklin",
        "organization": "Acme Inc",
        "phones": [{ "value": "+14155551234", "label": "mobile" }],
        "emails": [{ "value": "sean@acme.example", "label": "work" }]
      }
    }'
  ```

  ```js Node.js theme={null}
  const ts = Math.floor(Date.now() / 1000)
  const body = JSON.stringify({
    contact: {
      full_name: "Sean Franklin",
      given_name: "Sean",
      family_name: "Franklin",
      organization: "Acme Inc",
      phones: [{ value: "+14155551234", label: "mobile" }],
      emails: [{ value: "sean@acme.example", label: "work" }],
    },
  })
  const sig = crypto.createHmac("sha256", SIGNING_SECRET).update(`${ts}.${body}`).digest("hex")
  const res = await fetch(
    `https://console.trychert.com/api/v1/chats/${chatId}/send-contact`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-chert-tenant": TENANT_SLUG,
        "x-chert-signature": `v1,${ts},${sig}`,
      },
      body,
    },
  )
  ```

  ```python Python theme={null}
  import hmac, hashlib, json, time, requests
  ts = int(time.time())
  body = json.dumps({
      "contact": {
          "full_name": "Sean Franklin",
          "given_name": "Sean",
          "family_name": "Franklin",
          "organization": "Acme Inc",
          "phones": [{"value": "+14155551234", "label": "mobile"}],
          "emails": [{"value": "sean@acme.example", "label": "work"}],
      },
  })
  sig = hmac.new(SIGNING_SECRET.encode(), f"{ts}.{body}".encode(), hashlib.sha256).hexdigest()
  r = requests.post(
      f"https://console.trychert.com/api/v1/chats/{chat_id}/send-contact",
      headers={
          "Content-Type": "application/json",
          "x-chert-tenant": TENANT_SLUG,
          "x-chert-signature": f"v1,{ts},{sig}",
      },
      data=body,
  )
  ```
</RequestExample>

## Response

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "chat_id": "ch_01H...",
    "status": "sent"
  }
  ```
</ResponseExample>

### Path parameters

<ParamField path="id" type="string">
  Chat identifier (`ch_…`). Omit and use `body.to` for first-touch recipients with no chat yet.
</ParamField>

### Body

Provide either a `contact` object (canonical) **or** a raw `vcard_text` string.

<ParamField body="to" type="string">
  Recipient phone in E.164 format. Use instead of the `{id}` path segment when no chat exists yet. Ignored when `{id}` is supplied.
</ParamField>

<ParamField body="contact" type="object">
  Canonical contact wrap. Must include at least one identifying field.

  ```jsonc theme={null}
  {
    "full_name": "Sean Franklin",
    "given_name": "Sean",
    "family_name": "Franklin",
    "organization": "Acme Inc",
    "phones": [{ "value": "+14155551234", "label": "mobile" }],
    "emails": [{ "value": "sean@acme.example", "label": "work" }]
  }
  ```

  | Field          | Type      | Notes                                      |
  | -------------- | --------- | ------------------------------------------ |
  | `full_name`    | string    | Formatted display name.                    |
  | `given_name`   | string    | First name.                                |
  | `family_name`  | string    | Last name.                                 |
  | `organization` | string    | Org / company name.                        |
  | `phones`       | object\[] | Each `{ value: <E.164>, label?: string }`. |
  | `emails`       | object\[] | Each `{ value, label?: string }`.          |
</ParamField>

<ParamField body="vcard_text" type="string">
  Raw vCard payload (begins with `BEGIN:VCARD`). Use this when you already produce vCards elsewhere.
</ParamField>

### Response fields

<ResponseField name="chat_id" type="string">
  The chat the card was sent into.
</ResponseField>

<ResponseField name="status" type="string">
  Always `"sent"` on success.
</ResponseField>

## Errors

| Code   | HTTP | When                                                                                                     |
| ------ | ---- | -------------------------------------------------------------------------------------------------------- |
| `1001` | 400  | Missing `contact` and `vcard_text` (request body needs one of them).                                     |
| `1002` | 400  | `contact` has no identifying field, or fields were supplied in an unsupported shape.                     |
| `1004` | 400  | Invalid JSON body.                                                                                       |
| `2002` | 404  | Chat not found. On first-touch with no existing chat, address the call with `body.to` instead of `{id}`. |
| `4001` | 502  | Delivery failed.                                                                                         |
| `4099` | 501  | No pinned line, or the line does not support contact bubbles.                                            |

See the full [error code reference](/api/errors).

## See also

* [Share line's contact info](/api/contact-sharing/share-info)
* [Errors](/api/errors)
