Skip to content
View as Markdown

Set a contact card

A contact card is the name and photo recipients see at the top of a conversation with one of your lines — the iMessage “Share Name and Photo” identity. These endpoints create it, read back what the line actually holds, and share it into a conversation, so a new line can be branded without anyone touching the Mac.

POST/set-contact-cardBearer token
The usual sequence
  1. Create — POST /set-contact-card with name and photo. Read status.
  2. Verify — GET /get-contact-card. The line reports its live name and photo; line.state should be APPLIED.
  3. Share — POST /share-contact-card to a destination you have already messaged.
  4. Update — POST /set-contact-card again with only the fields that change; the rest stays.
  5. Reshare — share again. A fresh card revision is never collapsed as a duplicate.

Creates the line's card on the first call and updates it on later ones. Omitted fields keep their current value, so a name-only update leaves the photo alone. The photo is fetched (or decoded), centre-cropped to a 256 px square JPEG, stored, and pushed to the line in one request. Expect a few seconds; the line has to persist the card through Messages before it answers.

Request body

lineIdstring (UUID v4)Required
The line whose iMessage name and photo to set. Use a lineId returned from GET /get-lines.
firstNamestring
First name shown in the recipient's Messages header. 1–64 characters. Required when the line has no contact card yet; omitted on a later call keeps the current value.
lastNamestring
Last name shown next to firstName. Same rules as firstName. Many customers put the business name here.
imageUrlstring (https URL) | null
Public https URL of the photo. JPEG, PNG, WebP, GIF or HEIC up to 10 MB; it is centre-cropped to a 256 px square JPEG before it reaches the line. Pass null to remove the photo. Omit to keep the current one. Private and internal hosts are rejected.
imageBase64string
The photo as base64 (a data: URL is accepted). Same formats and cap as imageUrl. Mutually exclusive with imageUrl.
Read status, not the HTTP code
The line reports the name and the photo separately, and the response passes that through rather than rounding it up to success:
  • APPLIED (200) — the line confirmed everything you sent.
  • PARTIAL (200, error_code: PHOTO_NOT_APPLIED) — the name landed but the photo did not. The stored card keeps its previous photo. Retry with a different image.
  • FAILED (4xx / 502) — nothing changed. error_code says why; see the table below.
  • INDETERMINATE (504, error_code: DEVICE_TIMEOUT) — the line did not answer in time. The card may or may not have applied. Call GET /get-contact-card; do not assume either way.

The contactCard object

cardIdstringRequired
Opaque id of the stored card. Do not parse it.
firstNamestringRequired
Stored first name.
lastNamestringRequired
Stored last name.
imageUrlstring | nullRequired
Public URL of the normalised photo Project Blue stored, or null when the card has no photo.
hasPhotobooleanRequired
Whether the stored card carries a photo.
appliedToLinebooleanRequired
True once the line confirmed this exact card. False after a PARTIAL or INDETERMINATE set, or when GET /get-contact-card found the line showing something else.
updatedAtstring (ISO-8601)Required
When the stored card last changed.

Status codes

200
APPLIED or PARTIAL — see status.
400
Bad input (CONTACT_CARD_NAME_REQUIRED on a first call without both names; IMAGE_INVALID, IMAGE_TOO_LARGE, IMAGE_FETCH_FAILED, IMAGE_URL_NOT_ALLOWED for the photo).
401
Missing or invalid API key.
403
Trial account, or LINE_NOT_ELIGIBLE — an SMS-only or shared line has no iMessage identity to set.
409
The line cannot take the change yet: LINE_UNSUPPORTED_SERVER (needs BlueBubbles 2.2.0+), LINE_PRIVATE_API_DISABLED, LINE_HELPER_DISCONNECTED, LINE_NOT_REGISTERED_IMESSAGE, or LINE_NOT_PROVISIONED. Contact support.
429
Rate limit exceeded.
502
DEVICE_REJECTED — the line refused the card; or IMAGE_STORAGE_FAILED before anything reached the line.
503
LINE_OFFLINE — the line did not answer the readiness check. Nothing changed; retry shortly.
504
INDETERMINATE — read the card back.
Idempotency
An identical request (same line, names and image) within a short window is collapsed and the first result replayed with deduped: true. Pass an Idempotency-Key header to control this yourself. An INDETERMINATE result is never cached, so a retry after a timeout does run again — the line applies the same card twice harmlessly.
API reference