Skip to content
← BlogDeveloperAnalysis6 min read

Why Norbelys's API uses givenName, not first_name

Norbelys's API uses Schema.org fields — givenName, affiliation, sameAs — instead of bespoke names like first_name. The reasoning, plus the mapping table.

By Gabriel Lara, Developer Relations, Norbelys

Founder-reviewed ·How we research and correct articles

Open the response from GET /v1/people/:id and you won’t see first_name, company, or linkedin_url. You’ll see givenName, affiliation, and sameAs. That’s not an aesthetic choice or a nod to some internal style guide — it’s Schema.org, the vocabulary schema.org’s Person and Organization types already define, reused instead of reinvented. The reasoning behind it is worth understanding, because it explains a design decision that shows up in every response the API returns.

The problem with inventing your own names

Every API that models a person ends up needing a name for “the person’s first name.” Most invent one: first_name, firstName, fname, given_name. All four exist across real production APIs today, and none of them is wrong — they’re just arbitrary, which means every integration has to look them up. That’s a cost paid once per API, forever, by every developer and every tool that touches it, for a decision that had no reason to be made fresh in the first place.

Schema.org already solved this. It’s the vocabulary search engines, structured-data tooling, and a large share of the web’s own JSON-LD already speak — Person.givenName, Person.familyName, Organization.name, Thing.sameAs. It’s not a cold-email-specific vocabulary; it’s a general one that happens to cover exactly the entities a CRM-shaped API needs to name: people, organizations, addresses, URLs. Reusing it means the names on the wire are recognizable before you’ve read a single line of documentation, because they’re the same names schema.org, and by extension a large amount of existing tooling, already treats as standard.

curl https://api.norbelys.com/v1/people/con_8h3k \
  -H "Authorization: Bearer ak_live_..."
{
  "id": "con_8h3k",
  "email": "jane@acme.com",
  "givenName": "Jane",
  "familyName": "Doe",
  "jobTitle": "VP Marketing",
  "affiliation": "Acme Corp",
  "url": "https://acme.com",
  "sameAs": ["https://www.linkedin.com/in/janedoe"],
  "dateCreated": "2026-05-11T14:02:00Z"
}

Every one of those field names — givenName, jobTitle, affiliation, sameAs, dateCreated — is a real Schema.org property. None of it is Norbelys-invented.

Why this matters more with AI clients in the loop

The “already invented” argument gets stronger, not weaker, once you consider who else is reading these field names. A large language model has seen schema.org/Person and schema.org/Organization millions of times in its training data — in JSON-LD embedded across the web, in documentation, in other APIs that made the same choice. An AI agent driving Norbelys through the MCP server or generated SDKs is far more likely to correctly guess that affiliation means “company” than it is to guess that a bespoke company_name field does, because affiliation is vocabulary it’s already seen attached to exactly this meaning, thousands of times over. That’s the “AI-first” half of developer-first-and-AI-first: pick names a model already understands instead of ones it has to learn from your docs alone.

The full mapping

The person resource is the clearest example, and it’s also where this mattered enough to become a real migration: the resource used to be called contact, with firstName/lastName/phone fields, and the API was renamed end to end to match Schema.org — every field, not a partial relabeling. The mapping below is what that rename produced, and it’s the same mapping applied everywhere a comparable concept appears in the API:

Legacy field name API field (Schema.org) Type
firstName givenName Person
lastName familyName Person
email email Person
phone telephone Person
title jobTitle Person
companyName affiliation (or worksFor.name) Organization
website url Thing
linkedin sameAs Thing
location address PostalAddress
customFields additionalProperty PropertyValue[]
createdAt dateCreated
updatedAt dateModified

additionalProperty is worth calling out specifically — it’s Schema.org’s own mechanism for “a named value that doesn’t fit the standard vocabulary,” which is exactly what a custom field is. Rather than inventing yet another bespoke shape for user-defined fields, the API reuses the vocabulary’s own extension point.

Where Schema.org doesn’t reach

Not everything in a cold-email platform has a Schema.org equivalent, and the rule isn’t to force one where it doesn’t fit. Fields with no real counterpart — status, source, dailyLimit, and similar Norbelys-specific concepts — stay as descriptive lowerCamelCase names, exactly as bespoke as they’d be in any other API. The rule is narrower and more useful than “always use Schema.org”: use it where it already exists, and don’t invent around it where it doesn’t. That keeps the vocabulary honest instead of stretching it to cover things it was never meant to describe.

Committed to, not just applied on top

It’s worth being precise about what “the API is renamed end to end” actually means, because it’s a stronger claim than most API migrations make. It would have been easy to keep the old contact/firstName/lastName names as the real ones and just relabel them in a thin response layer — cheaper, lower-risk, shippable in an afternoon, and invisible to anyone reading the docs. Norbelys did the more thorough thing instead: contact became person, firstName became givenName, lastName became familyName, phone became telephone, and importBatchId became importId, consistently across the whole surface — not a facade dressed up to look renamed. The ID prefix (con_…) stayed the same on purpose — it’s an opaque identifier, not a name, so there was nothing to correct there, and changing it would have broken every existing reference for no benefit.

That matters for correctness, not just cleanliness. A half-applied rename is where bugs hide — one endpoint using the new name while another quietly still returns the old one. Doing it consistently, everywhere the concept appears, removes that class of inconsistency instead of leaving it for an integrator to discover the hard way. It’s the same “fewest moving parts” instinct that puts a plain Idempotency-Key header directly on state-changing requests instead of asking integrators to build their own out-of-band deduplication — solve the problem once, at the source, rather than papering over it downstream.

What this buys you as an integrator

In practice this means you can often guess a field name correctly before checking the OpenAPI spec, and when you do check it, the name will already make sense rather than needing a lookup table of your own. It’s the same principle behind the five endpoint patterns the whole API follows — fewer arbitrary decisions on the wire means less the API asks you to memorize and more it lets you predict. A Person is the same Person whether Schema.org, Norbelys, or the LLM reading your integration code is the one looking at it.

Frequently asked questions

Why does the person resource still use the con_ ID prefix if it's no longer called contact?

IDs are opaque identifiers, not names — they're prefixed cuid2 values used to identify a record type in logs and URLs, not to describe what the resource is called in the API. The rename changed every field name to Schema.org vocabulary; it left the con_ prefix alone because there was nothing wrong with it.

Do all Norbelys resources use Schema.org names?

Only where a genuine equivalent exists, which is mostly the person and organization-shaped fields. Domain-specific concepts like sending status, daily limits, or campaign state have no Schema.org counterpart and use descriptive camelCase names instead, same as any other API.

What is additionalProperty for?

It's Schema.org's own extension mechanism for values that don't map to a standard property. Norbelys uses it to represent custom fields you define on a person, so user-defined data has a real Schema.org shape instead of an ad hoc key-value bag.