Set a contact photo
Uploads the photo shown for a contact, replacing any there was. The body is the image itself, not JSON, with its type in `Content-Type`: `image/png`, `image/jpeg`, `image/webp` or `image/gif`, up to 5 MB. It is fitted into a 512 pixel square and stored as WebP, and an animated image keeps its first frame.
Runs the real call against your workspace, with your own key.
PUT /contacts/{email}/photo
Uploads the photo shown for a contact, replacing any there was. The body is the image itself, not JSON, with its type in Content-Type: image/png, image/jpeg, image/webp or image/gif, up to 5 MB. It is fitted into a 512 pixel square and stored as WebP, and an animated image keeps its first frame.
Example
Needs contacts:write. The address has to be a saved contact, so save it with PUT /contacts/{email} first.
curl -X PUT "$OE/contacts/grace%40example.com/photo" -H "$AUTH" -H 'content-type: image/jpeg' --data-binary @grace.jpg{ "object": "contact", "email": "[email protected]", "name": "Grace Hopper", "source": "manual", "notes": null, "photoUrl": "https://cdn-prod.openemail.uk/contacts/photos/5b0e2c7a-91d4-4f3e-8a26-c4f1d9e07b3a.webp", "lastSeenAt": null, "createdAt": "2026-09-18T09:00:00.000Z", "updatedAt": "2026-09-23T10:20:00.000Z", "audiences": [ { "id": "aud_9f2c4b7e1a0d63d84c5f2e7b", "name": "All contacts", "builtin": "default" } ]}An address that is not a saved contact is a 404 contact_not_found. A body that is not an image of an accepted type, is larger than 5 MB or cannot be read is a 422 invalid_image.
A saturated image service answers 503 image_busy, which is safe to retry. Every upload gets a new photoUrl, so a cached old photo never shows under the new one.