create_contact is that way in.
The record it writes is a full vCard-shaped one, not just a routing target: alongside the name and email addresses it holds phone numbers, structured postal addresses, an organization, and a free note. A contact does not need an email address — a name and a postal address is a valid record.
Search with search_contacts first. If the person is already known, use update_contact instead, so their interaction history stays on one record.
Parameters
string
required
The display name, 1–200 characters.
object[]
Up to 10 entries, each
{ address, context? }. context is work or private; when omitted it is inferred from the domain.object[]
Up to 10 entries, each
{ number, label? }. label is mobile, home, work, fax, or other (the default).object[]
Up to 5 entries, each
{ street?, postalCode?, city?, region?, country?, label? }. At least one of street, postalCode, city, or region is required. country is an ISO 3166-1 alpha-2 code such as DE — convert a country name yourself. label is home, work, or other (the default).string
Company or organization, 1–200 characters.
string
Free-text note, up to 2000 characters.
Why postal addresses are structured
A single free-text block is easier to write and harder to use. Address formats are country-specific, and an agent addressing a letter needs the components separately. The components map onto the standard JSContact address model, so a CardDAV client renders them the way it renders any other contact’s address.Example
Call
Result
contact_id addresses the record in update_contact and delete_contact. The [a0]-style handles address one postal address or phone number within it.
The contact is written to the account’s default address book — never to the machine-maintained Collected book, which is where derivation puts what it infers.
Provenance
Every contact carries asource:
The marker matters because a confidence rating means different things across them: confidence in a derived address is an inference from headers, confidence in an authored one is the user’s own assertion. Collection only ever fills blanks on a record, so nothing typed here is overwritten by what Langmail later infers — and a later sighting never relabels an authored record as derived.
Errors
<address> already belongs to an existing contact (contact_id: …)— the address is on another card. Useupdate_contactagainst that id instead of splitting the person across two records.a postal address needs at least a street, city, postal code, or region— a postal address entry carried only a label.- Schema rejection on
country— pass a two-letter ISO 3166-1 alpha-2 code, not a country name.