Contacts
List, search and write contacts across Google, Microsoft 365 and CardDAV, with photos.
Contacts and sync
Google (People API) and Microsoft 365 accounts sync their contacts when the account's contactsEnabled setting is on; IMAP accounts sync over CardDAV once their IMAP settings name a CardDAV server. Reads come from workwae's index; writes go to the provider first, then to the index, so a new contact is listed at once. Without contacts sync these routes answer 409 contacts_disabled; a plan without the contacts module answers 403 plan_module_unavailable.
List and search
q matches part of any name, the organization or any email address, ignoring case. Pages hold up to 500 contacts.
Microsoft 365 contacts live in folders: GET .../contact-folders lists them (the default folder first; always empty for Google), and folderId narrows the list to one.
Create, change and delete
A new contact needs at least a name, an organization, an email address or a phone number (contact_unidentifiable otherwise).
// Fields present change, null clears; emails and phones replace the whole list.
await workwae.contacts.update({
accountId,
contactId: contact.id,
jobTitle: "Mathematician",
phones: [],
});
await workwae.contacts.delete({ accountId, contactId: contact.id });| Provider | What it stores |
|---|---|
No folders (folderId is refused). A birthday may omit the year: --12-10. | |
| Microsoft 365 | At most 3 email addresses, one mobile number, and no other phone type; email addresses carry no type. More is refused as provider_unsupported. |
| CardDAV | Whatever the server keeps; at most 20 emails and phones each, as everywhere. |
Photos
GET .../contacts/{contactId}/photo answers the photo as the provider stores it (image/jpeg, image/png, ...), fetched on first request and cached until it changes. hasPhoto says whether there is one (null on Microsoft 365, which does not say without fetching it); a contact without one answers 404 photo_not_found.
const photo = await workwae.contacts.photo({ accountId, contactId }); // a File
await Bun.write(`${contactId}.${photo.type.split("/")[1]}`, photo);Contact events
contact.created,contact.updated(naming the changed fields,photofor a new picture) andcontact.deletedreport changes made anywhere: through the API, in Gmail or Outlook, or on the CardDAV server.contacts.initializedmarks the end of an account's first contacts sync; nothing from before it is announced contact by contact.