---
name: manage-customer-profiles-in-people
description: Create, match, upsert and merge person profiles in the Infobip People CDP so messaging and
  journeys resolve to one customer.
api: openapi/infobip-people-openapi.json
operations:
- get-a-single-person-or-a-list-of-people
- create-a-new-person
- partial-person-update
- upsert-persons-partial
- match-people-ids
- merge-persons
- batch-people-create
- set-person-contact-information
provider: Infobip
generated: '2026-07-25'
method: generated
source: Grounded in operationIds verified in openapi/infobip-people-openapi.json plus conventions/infobip-conventions.yml,
  errors/infobip-error-codes.yml and rate-limits/infobip-rate-limits.yml
---

# Manage customer profiles in People

Create, match, upsert and merge person profiles in the Infobip People CDP so messaging and journeys resolve to one customer.

## Ground rules for every Infobip call

- Base URL: `https://api.infobip.com` (an account may also be issued a personalized `https://{subdomain}.api.infobip.com` host shown in the web portal — either works).
- Auth header: `Authorization: App {API_KEY}`. Basic auth is only for the API-key-management endpoints. Every endpoint additionally requires at least one API scope (see `scopes/infobip-scopes.yml`).
- There is **no idempotency key**. Never blind-retry a send on a timeout or 5xx — re-read the outcome with the reports/logs operation for the returned `bulkId`/`messageId` first (`conventions/infobip-conventions.yml`).
- On `429` back off exponentially and honour `Retry-After`. Per-operation limits are published in the spec as `x-throttling-info` and collected in `rate-limits/infobip-rate-limits.yml`.
- HTTP errors use the Infobip `requestError.serviceException {messageId, text, validationErrors}` envelope (not RFC 9457) — see `errors/infobip-problem-types.yml`.
- A `200` does **not** mean delivered. Message outcome lives in the `status {groupId, groupName, id, name}` and `error {groupId, groupName, id, name, permanent}` objects; resolve them against `errors/infobip-error-codes.yml`. `permanent: true` means a retry can never succeed.
- Listing endpoints page with `page`/`size` (max 100) and return `{page, size, totalPages, totalResults}`; newer endpoints support `cursor`/`useCursor`.

## Steps
1. **Look before you create** — `get-a-single-person-or-a-list-of-people` (`GET /people/2/persons`) accepts `identifier` + `type` (for example a phone number or email) so you can resolve an existing profile instead of duplicating it. Listing is paged with `page`/`size` and `includeTotalCount`.
2. **Create** — `create-a-new-person` (`POST /people/2/persons`), or `batch-people-create` (`POST /people/2/persons/batch`) for bulk loads.
3. **Prefer upsert for sync jobs** — `upsert-persons-partial` (`PATCH /people/3/persons/upsert`) or `upsert-persons-full` (`PUT /people/3/persons/upsert`). This is the closest thing the platform has to an idempotent write: repeating the same upsert converges instead of duplicating, which matters because there is no `Idempotency-Key`.
4. **Resolve identities in bulk** — `match-people-ids` (`POST /people/2/persons/match`) takes a list of identities and returns the internal person id for each; duplicate identities collapse to a single profile reference.
5. **Fix duplicates** — `merge-persons` (`POST /people/3/persons/merge`).
6. **Contact channels** are managed separately: `set-person-contact-information`, `add-person-contact-information`, `delete-person-contact-information` on `/people/2/persons/contactInformation`.
7. Throttling here is tight (roughly 5–10 requests/second on the person endpoints) — batch rather than loop, and honour `Retry-After` on `429`.
