Send a contact card and the recipient sees a rich contact preview they can tap
to save directly to their contacts, with call / text / email action buttons.
Pass the contact fields directly to sendContactCard — the SDK generates the
vCard, uploads it, and attaches it to a message in one call.
import { createClient } from "@messages-dev/sdk";
const client = createClient();
await client.sendContactCard({
from: "+15551234567",
to: "+15559876543",
firstName: "Jane",
lastName: "Doe",
phones: [{ type: "cell", value: "+15559876543" }],
emails: [{ value: "jane@acme.com" }],
org: "Acme Corp",
title: "Head of Engineering",
});
# 1. Upload the vCard file
curl -X POST "https://api.messages.dev/v1/files" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: text/vcard" \
-H "X-Filename: jane-doe.vcf" \
--data-binary @jane-doe.vcf
# Response: { "id": "file_...", ... }
# 2. Send it as an attachment
curl -X POST "https://api.messages.dev/v1/messages" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"from": "+15551234567",
"to": "+15559876543",
"attachments": ["file_..."]
}'
Include at least one phones or emails entry. iOS uses them to render the
tappable action buttons (call, text, email) on the contact preview.
Supported fields
| Field | Type | Description |
|---|
firstName, lastName | string | Required. Used for both N and FN in the vCard. |
phones | { value, type? }[] | One or more phone numbers. type defaults to cell. |
emails | { value, type? }[] | One or more email addresses. type is optional. |
org | string | Organization / company. |
title | string | Job title. |
url | string | Website. |
address | { street?, city?, region?, postalCode?, country?, type? } | Mailing address. |
bday | string | Birthday, ISO YYYY-MM-DD. |
note | string | Free-text note. Reserved characters (;, ,, newlines) are escaped automatically. |
photo | string | File ID (file_...) of a JPEG or PNG uploaded via POST /v1/files. The SDK fetches it and embeds it inline in the vCard. |
photoType | "JPEG" | "PNG" | Override photo mime type when auto-detection from the file’s magic bytes can’t determine it. |
text | string | Optional message text sent alongside the card. |
replyTo | string | Message ID or GUID to reply to. |
filename | string | Override the uploaded .vcf filename. Default: <first>-<last>.vcf. |
Upload the photo via POST /v1/files first, then pass the returned file ID
as photo. The SDK downloads it, sniffs the image type (JPEG / PNG), and
embeds it inline in the vCard.
import { readFileSync } from "node:fs";
import { createClient } from "@messages-dev/sdk";
const client = createClient();
const photo = await client.uploadFile({
file: readFileSync("jane.jpg"),
mimeType: "image/jpeg",
filename: "jane.jpg",
});
await client.sendContactCard({
from: "+15551234567",
to: "+15559876543",
firstName: "Jane",
lastName: "Doe",
phones: [{ type: "cell", value: "+15559876543" }],
photo: photo.id,
});
Keep photos small (under 100KB) for the best delivery experience. Large photos
inflate the vCard significantly once base64-encoded.
Advanced: custom vCard
If you need fields that sendContactCard doesn’t expose (exotic TYPE
combinations, custom X- extensions, multiple addresses), build the vCard
yourself and send it via the file + attachment flow:
import { createClient } from "@messages-dev/sdk";
const client = createClient();
const vcard = [
"BEGIN:VCARD",
"VERSION:3.0",
"N:Doe;Jane;;;",
"FN:Jane Doe",
"TEL;TYPE=CELL:+15559876543",
"EMAIL:jane@acme.com",
"END:VCARD",
].join("\r\n");
const file = await client.uploadFile({
file: new Blob([vcard], { type: "text/vcard" }),
filename: "jane-doe.vcf",
mimeType: "text/vcard",
});
await client.sendMessage({
from: "+15551234567",
to: "+15559876543",
attachments: [file.id],
});
For reference when building custom vCards, a full-featured example:
BEGIN:VCARD
VERSION:3.0
N:Doe;Jane;;;
FN:Jane Doe
ORG:Acme Corp
TITLE:Head of Engineering
TEL;TYPE=CELL:+15559876543
TEL;TYPE=WORK:+15551112222
EMAIL:jane@acme.com
URL:https://acme.com
ADR;TYPE=WORK:;;123 Main St;San Francisco;CA;94105;US
NOTE:Met at WWDC 2025
END:VCARD
Common fields
| Field | Example | Description |
|---|
N | Doe;Jane;;; | Last; First; Middle; Prefix; Suffix |
FN | Jane Doe | Full display name |
TEL;TYPE=CELL | +15559876543 | Mobile phone |
TEL;TYPE=WORK | +15551112222 | Work phone |
EMAIL | jane@acme.com | Email address |
ORG | Acme Corp | Organization |
TITLE | Head of Engineering | Job title |
URL | https://acme.com | Website |
ADR;TYPE=WORK | ;;123 Main St;City;ST;ZIP;US | Address |
NOTE | Met at WWDC 2025 | Free-text note |
BDAY | 1990-06-15 | Birthday |
PHOTO;ENCODING=b;TYPE=JPEG | <base64> | Inline photo |
The MIME type for vCard files is text/vcard, the file extension is .vcf,
and lines are joined with \r\n.