Everything the CardDAV server serves is vCard 3.0, folded at 75 characters with CRLF as required by RFC 2425. Contacts in the personal and shared books are mapped from the phonebook, contacts in the colleagues book are generated from the employee, their PBX extensions and their MVNO numbers.
| vCard property | Phonebook field | Note |
|---|---|---|
UID | _id | The contact id. Also the file name of the resource. |
FN | givenName + familyName | For a company contact the company name. |
N | familyName;givenName | Empty (N:;;;;) for a company contact. |
ORG | company[;department] | A contact with only a department gets ORG:;<department>. |
X-ABShowAs | type | COMPANY for company contacts, which is what makes Apple show it as a company. |
TITLE | title | |
TEL;TYPE= | phoneNumbers[] | One line per number, the phonebook type mapped to a vCard type. |
EMAIL;TYPE= | emailAddresses[] | One line per address. Type MAIN is served as WORK. |
ADR;TYPE= | addresses[] | Street, city, state, zip and country in the structured vCard order. |
NOTE | notes | Shared contacts are prefixed [Shared Contact]. |
CATEGORIES | - | Shared on contacts from the shared book. |
X-SHORT-NUMBER | shortNumber | |
X-EXTERNAL-ID | externalId | The id in the system the contact was imported from, e.g. MS365. |
PHOTO;VALUE=URI | picture | https://image.telecomx.dk/<picture>.jpeg?width=400&height=400&token=<token>. A URL rather than embedded base64, so the device fetches the picture itself. |
REV | updatedAt | Falls back to createdAt, and for contacts written directly to the database by an importer to the timestamp inside the _id - never to now, which would make the client re-sync the contact forever. |
| vCard property | Source | Note |
|---|---|---|
UID | Employee _id | |
FN / N | Employee name | Split on the last space: everything before it is the given name. |
ORG | Customer name[;employee department] | |
TITLE | Employee title | |
TEL;TYPE=WORK | Extension number | One per extension, plus an X-SHORT-NUMBER with the same value. |
TEL;TYPE=PREF | Extension direct | The direct dial number. |
TEL;TYPE=CELL | MVNO numbers[0] | The first number of each MVNO account attached to one of the extensions. |
EMAIL;TYPE=WORK | Employee emailAddress | |
ADR;TYPE=WORK | Customer address | The address on the employee, or the customers primary address if the employee has none. |
PHOTO;VALUE=URI | Employee picture | Same image server URL as above. |
NOTE / CATEGORIES | - | Always [Colleague] and Colleague. |
REV | Newest of employee, extension and MVNO updatedAt | The same timestamp is used for the ETag, so any of the three changing re-syncs the card. |
Only employees with at least one extension that has phonebook enabled are included, and deleted employees are left out.
BEGIN:VCARD VERSION:3.0 UID:1234567890ABCDEF12345678 FN:Jane Doe N:Doe;Jane;;; ORG:Example Company A/S;Support TITLE:Support manager TEL;TYPE=WORK:101 X-SHORT-NUMBER:101 TEL;TYPE=PREF:70123456 TEL;TYPE=CELL:20123456 EMAIL;TYPE=WORK:jane@example.dk ADR;TYPE=WORK:;;Eksempelvej 1;København;;2100;DK PHOTO;VALUE=URI:https://image.telecomx.dk/234567890ABCDEF123456789.jpeg?width=40 0&height=400&token=eyJhbGciOi... NOTE:[Colleague] CATEGORIES:Colleague REV:20260901T081500Z END:VCARD
This is the other direction, used when a device writes a contact with PUT. Properties not listed here are ignored, so a client that stores extra fields will silently lose them.
| vCard property | Phonebook field |
|---|---|
UID | _id, when it is a 24 character hex string |
N | familyName, givenName |
FN | company, but only when N and ORG gave nothing |
ORG | company, department |
TITLE | title |
X-ABSHOWAS:COMPANY | type = company, and the parsed names are dropped |
TEL | phoneNumbers[], the vCard type mapped back to a phonebook type |
EMAIL | emailAddresses[] |
ADR | addresses[], typed HOME or WORK (anything else becomes WORK) |
NOTE | notes, with a leading [Shared Contact] stripped |
X-SHORT-NUMBER | shortNumber |
X-EXTERNAL-ID | externalId |
PHOTO | picture - see below |
Grouped properties (item1.TEL, which is what Apple writes) are understood, as are folded lines and escaped values.
| Phonebook type | vCard TYPE |
|---|---|
MOBILE | CELL (MOBILE is also accepted on the way in) |
MAIN | PREF (MAIN is also accepted on the way in) |
WORK | WORK |
HOME | HOME |
OTHER | OTHER, and anything unrecognised |
E-mail addresses use the same names, except that a MAIN address is served as WORK. Addresses are HOME or WORK; anything else becomes WORK.
A PHOTO in an incoming vCard is accepted as base64, as a data: URL or as an http(s) URL. It is uploaded to the image server and the contact then references the stored image. Dropping the PHOTO property from a vCard deletes the picture; the old image is only deleted after the contact has been saved.
Because the client controls the URL, it is validated before it is fetched: private ranges (10/8, 172.16/12, 192.168/16), loopback, link-local and the Telecom X server range 62.192.160.0/24 are refused, and host names are resolved first so a name pointing at an internal address is caught as well.
| Value | Format |
|---|---|
| ETag, phonebook contact | “<updatedAt in ms>”. Contacts from before updatedAt existed fall back to an MD5 of the contact data. |
| ETag, colleague | “<newest updatedAt in ms>” across the employee, their extensions and their MVNO accounts. |
| CTag | <number of contacts>-<newest updatedAt in ms>, or “empty” for an empty book. |