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

# Contact cards

> Save vCards once and send them as native contact cards that recipients can save in one tap.

A contact card (vCard) arrives on the recipient's phone as a native card they can save to their contacts in one tap. Save a card once with `POST /v1/vcards` and send it by ID with a `vcard` part, or send your own `.vcf` file as media. Contact cards work in direct and group chats, over iMessage, RCS and SMS, once the contact has replied to your number.

> [!WARNING]
>
> A contact card can't go in a first message or in any message before the contact replies. Blujay rejects it with `400` [`PRE_REPLY_CONTENT_BLOCKED`](/errors/pre-reply-content-blocked) and nothing is sent. Introduce yourself in text first, then send the card. See [Sending rules](/messaging/sending-rules.md).

> [!NOTE]
>
> A contact card is a file the recipient can save. It doesn't change the name or photo that Messages shows for your Blujay number.

## Save a card

```bash theme={null}
curl https://api.blujay.io/v1/vcards \
  -H "Authorization: Bearer blu_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Northwind",
    "last_name": "Support",
    "company": "Northwind Supply",
    "title": "Customer Support",
    "phones": [
      { "number": "+15555550100", "type": "work" }
    ],
    "emails": [
      { "address": "support@example.com", "type": "work" }
    ],
    "website": "https://example.com/support"
  }'
```

```json 201 Created theme={null}
{
  "status": "success",
  "data": {
    "id": "vcard_abc123",
    "first_name": "Northwind",
    "last_name": "Support",
    "company": "Northwind Supply",
    "title": "Customer Support",
    "phones": [{ "number": "+15555550100", "type": "work" }],
    "emails": [{ "address": "support@example.com", "type": "work" }],
    "website": "https://example.com/support",
    "has_photo": false,
    "created_at": "2026-10-14T17:00:00.000Z",
    "updated_at": "2026-10-14T17:00:00.000Z"
  },
  "trace_id": "trc_8b1e4d07a2c5",
  "timestamp": "2026-10-14T17:00:00.000Z"
}
```

The card's ID comes back as `id`, not `vcard_id`. Most Blujay resources name their ID `<resource>_id`; saved cards and team members use `id`. Use that `id` as `vcard_id` in a `vcard` part and in the `/v1/vcards/{vcard_id}` path.

| Field | Rules |
| - | - |
| `first_name` | Required. Up to 80 characters. |
| `last_name` | Optional. Up to 80 characters. |
| `company`, `title` | Optional. Up to 120 characters each. |
| `phones` | Up to 5. Each has a `number` in E.164 (`+15555550100`) and a `type`: `mobile` (the default), `work`, `home` or `main`. The first number is the card's preferred number. |
| `emails` | Up to 5. Each has an `address` and a `type`: `work` (the default), `home` or `other`. |
| `website` | Optional. An `http` or `https` URL. |

A card needs at least one phone number or email. Recipients see each `type` as the label next to the number or address. Unknown fields are rejected with `400` [`VALIDATION_ERROR`](/errors/validation-error).

Card photos are managed in the Blujay app. `has_photo` tells you whether a card has one, and a card with a photo is sent with it.

## Send a saved card

Add a `vcard` part with the card's ID to a follow-up in a chat where the contact has already replied:

```bash theme={null}
curl https://api.blujay.io/v1/chats/chat_abc123/messages \
  -H "Authorization: Bearer blu_your_api_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: support-card-chat_abc123" \
  -d '{
    "message": {
      "parts": [
        { "type": "text", "text": "Save our support number so you always know it is us." },
        { "type": "vcard", "vcard_id": "vcard_abc123" }
      ]
    }
  }'
```

```json 202 Accepted theme={null}
{
  "status": "success",
  "data": {
    "chat_id": "chat_abc123",
    "message": {
      "id": "msg_ghi789",
      "direction": "outbound",
      "delivery_status": "queued",
      "preferred_service": null,
      "service": null,
      "from": "+15555550100",
      "to": ["+15555550123"],
      "created_at": "2026-10-14T17:05:00.000Z",
      "parts": [
        { "type": "text", "text": "Save our support number so you always know it is us." },
        { "type": "media", "attachment_id": "att_def456" }
      ]
    }
  },
  "trace_id": "trc_c5a0e93f17b2",
  "timestamp": "2026-10-14T17:05:00.000Z"
}
```

Blujay builds the card file when it accepts the message, so the `vcard` part comes back as a `media` part with its own `attachment_id`. Message reads and webhooks show it the same way: a `media` part with `content_type` `text/vcard` and a `.vcf` file name built from the card's name, such as `Northwind Support.vcf`. The `vcard_id` isn't kept on the message, so a read can't tell you which saved card was sent. If you need that, record it against the `message_id` yourself when you send.

* A `vcard` part counts as a media part. It can sit next to `text` parts but not a `link`, and a message can have up to 40 `media` and `vcard` parts in total.
* Because the file is built at acceptance, later edits to the card never change a message you already sent. Retrying with the same `Idempotency-Key` returns the original message and doesn't build a second file.
* An unknown or deleted `vcard_id` returns `404` [`NOT_FOUND`](/errors/not-found) and nothing is sent.
* Before the contact replies, the send returns `400` [`PRE_REPLY_CONTENT_BLOCKED`](/errors/pre-reply-content-blocked) and nothing is sent.

A card a contact sends you arrives the same way: a `media` part with `content_type` `text/vcard`. Download it like any other [inbound media](/messaging/media.md#media-in-received-messages).

## Send your own `.vcf` file

If you already have a vCard file, send it like any other media, either uploaded or from a URL:

```json theme={null}
{ "type": "media", "url": "https://example.com/cards/northwind-support.vcf" }
```

Serve a vCard URL as `text/vcard` or `text/x-vcard`, or as a generic binary type with a `.vcf` file name. See [Media](/messaging/media.md) for uploads and URL rules.

## Manage saved cards

| Endpoint | What it does |
| - | - |
| `GET /v1/vcards` | Lists your saved cards, most recently updated first. Paginate with `limit` and `cursor`. |
| `GET /v1/vcards/{vcard_id}` | Returns one card. |
| `PATCH /v1/vcards/{vcard_id}` | Changes only the fields you send. The card must keep at least one phone number or email. |
| `DELETE /v1/vcards/{vcard_id}` | Deletes the card and returns `204`. Messages that already included it keep their copy. |

To update a card's title:

```bash theme={null}
curl -X PATCH https://api.blujay.io/v1/vcards/vcard_abc123 \
  -H "Authorization: Bearer blu_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Customer Support, 24/7" }'
```

Sending `phones` or `emails` in a `PATCH` replaces the whole list. Send `null` for `last_name`, `company`, `title` or `website` to clear it.

Saved cards are shared across your workspace, and your team sees the same cards in the Blujay app. Creating a card ignores `Idempotency-Key`; if a create times out, list your cards before you create it again.

> [!WARNING]
>
> **Common mistakes**
>
> * Sending a card before the contact replies returns `400` [`PRE_REPLY_CONTENT_BLOCKED`](/errors/pre-reply-content-blocked).
> * The create response names the ID `id`. Everywhere else it's `vcard_id`.
> * A `vcard` part can't share a message with a `link` part.
> * Reads show the card as `media` with `text/vcard`, never as a `vcard` part, and without the `vcard_id`.

## Limitations

* No contact cards until the contact replies (`400` [`PRE_REPLY_CONTENT_BLOCKED`](/errors/pre-reply-content-blocked)). See [Sending rules](/messaging/sending-rules.md).
* Free Plan numbers can't send to unverified contacts (`403` [`CONTACT_NOT_VERIFIED`](/errors/contact-not-verified)); AI Agent numbers only reply to people who text first (`403` [`CONTACT_MUST_TEXT_FIRST`](/errors/contact-must-text-first)). See [Plans](/plans.md).
* Card photos can only be set in the Blujay app. `has_photo` is read-only.
* A card needs at least one phone number or email, up to 5 of each (`400` [`VALIDATION_ERROR`](/errors/validation-error)).
* Sending a card doesn't change the name or photo Messages shows for your number.

## Next steps

> **[Media](/messaging/media.md)**
>
> Upload files and send media from URLs.

> **[Send messages](/messaging/send-messages.md)**
>
> Message parts, first messages and follow-ups.

> **[Group chats](/messaging/group-chats.md)**
>
> Share a card with everyone in a group.

> **[Contacts](/contacts.md)**
>
> Manage the people you message.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.