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
- Create —
POST /set-contact-cardwith name and photo. Readstatus. - Verify —
GET /get-contact-card. The line reports its live name and photo;line.stateshould beAPPLIED. - Share —
POST /share-contact-cardto a destination you have already messaged. - Update —
POST /set-contact-cardagain with only the fields that change; the rest stays. - 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)RequiredThe line whose iMessage name and photo to set. Use a lineId returned from GET /get-lines.
firstNamestringFirst 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.
lastNamestringLast name shown next to firstName. Same rules as firstName. Many customers put the business name here.
imageUrlstring (https URL) | nullPublic 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.
imageBase64stringThe 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_codesays 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. CallGET /get-contact-card; do not assume either way.
The contactCard object
cardIdstringRequiredOpaque id of the stored card. Do not parse it.
firstNamestringRequiredStored first name.
lastNamestringRequiredStored last name.
imageUrlstring | nullRequiredPublic URL of the normalised photo Project Blue stored, or null when the card has no photo.
hasPhotobooleanRequiredWhether the stored card carries a photo.
appliedToLinebooleanRequiredTrue 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)RequiredWhen the stored card last changed.
Status codes
- 200
- APPLIED or PARTIAL — see status.
- 400
- Bad input (
CONTACT_CARD_NAME_REQUIREDon a first call without both names;IMAGE_INVALID,IMAGE_TOO_LARGE,IMAGE_FETCH_FAILED,IMAGE_URL_NOT_ALLOWEDfor 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, orLINE_NOT_PROVISIONED. Contact support. - 429
- Rate limit exceeded.
- 502
DEVICE_REJECTED— the line refused the card; orIMAGE_STORAGE_FAILEDbefore 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.