> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paygentic.io/llms.txt
> Use this file to discover all available pages before exploring further.

# External Mappings

> Map records across external systems with the Item and ExternalReference resources

Paygentic often sits between external systems — a CRM, an ERP, a data warehouse, or any other. It needs a stable place to record "this external record is the same thing as that one." Two thin, billing-decoupled resources own that translation: the **`Item`** and the **`ExternalReference`**.

## Why these resources exist

Mapping between external systems is a pure translation — it never touches the billing engine. Rather than overload the billing `Product` with integration concerns, Paygentic models the mapping anchor as its own resource. The `Item` is the canonical "thing you sell"; the `ExternalReference` records each link from an `Item` to a record in an external system.

The `Item` is **CRM/ERP agnostic** — it knows nothing about which external systems map to it. All of that lives on its `ExternalReference` rows, where `provider` is just a lowercase identifier. A common use case is bridging an upstream CRM such as Salesforce to a downstream ERP such as NetSuite. The resources make no assumption about provider, direction, or authority — those are conventions a consumer layers on top.

<Note>
  The full design rationale (including the comparison to Orb's model and the variant analysis) lives in the [Item Resource — Design Rationale](https://linear.app/paygentic/document/item-resource-design-rationale-brainstorm-37bfbfc2fd3d) document on PAYG-1142.
</Note>

## The Item

An `Item` is intentionally thin — `id`, `merchantId`, `name`, and `metadata`. It carries no pricing, plan, currency, or metering, and it is independent of the billing `Product`.

```bash theme={null}
curl -X POST https://api.paygentic.io/v0/items \
  -H "Authorization: Bearer $PAYGENTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "merchantId": "org_…", "name": "Tines Enterprise License" }'
```

You can create an `Item` with just a name and attach external references later, in any order.

## The ExternalReference

An `ExternalReference` links an entity to its identifier in an external system. For mapping work the `entityType` is always `item`, and `provider` is a lowercase identifier such as `salesforce` or `netsuite`.

```bash theme={null}
curl -X POST https://api.paygentic.io/v0/externalReferences \
  -H "Authorization: Bearer $PAYGENTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "org_…",
    "entityType": "item",
    "entityId": "itm_…",
    "provider": "netsuite",
    "externalId": "1234",
    "externalLabel": "Cloud revenue"
  }'
```

The `entityId` must resolve to a live `Item` in the same merchant.

### Multiple references per provider

An `Item` may carry several references for the same provider. For example, aliases for renamed or legacy codes that all point at the same `Item`, or several valid downstream posting targets. Additional references beyond the primary are non-primary aliases (see below). A consumer selects the specific target it needs at the point of use.

### isPrimary vs isDefault

Two independent boolean flags express two different guarantees:

* **`isPrimary`** (default `true`) — at most one *primary* reference per `(merchant, provider, externalId)`. This is the deduplication guarantee: an external code is primary-linked to exactly one `Item`. Additional non-primary references with the same code are allowed as aliases.
* **`isDefault`** (default `false`) — at most one *default* target per `(merchant, entityType, entityId, provider)`. This is the optional "usually post to this target" hint. Most items set no default and force a selection at the point of use.

## Resolution

Resolve an external code to its `Item`(s) by listing with the `provider` + `externalId` filter (you must supply both together). Resolution returns **every** live `Item` mapped to that `(provider, externalId)` — the canonical primary plus any non-primary aliases. Resolution returns the primary `Item` **first**; its matching reference's `isPrimary: true` identifies it unambiguously (the partial-unique index guarantees **at most one** primary per code). An unknown code returns an empty list rather than an error.

Callers that only want the canonical owner take the first result; callers reconciling renamed or legacy codes get the full alias set.

```bash theme={null}
curl "https://api.paygentic.io/v0/items?merchantId=org_…&provider=salesforce&externalId=SKU_A" \
  -H "Authorization: Bearer $PAYGENTIC_API_KEY"
```

Fetching an `Item` returns its live external references in the `externalReferences` array. The `Item` itself reports no provider-specific lifecycle state. The consumer derives any gating (for example, "is this mapped to a downstream system yet?") from the presence of the relevant references. There is no hard stop at import time; an `Item` that carries only inbound references is still valid and simply has no downstream reference attached yet.

See the [API Reference](/openapi.json) for the full request and response schemas.
