Graine AI

Link identifiers to a person

Attach more identifiers to one of your users — a phone number, an email, your own user id — so that what your agents remember about them is found whichever one a later conversat…

Attach more identifiers to one of your users — a phone number, an email, your own user id — so that what your agents remember about them is found whichever one a later conversation comes in with: a call from the linked number, a chat signed in with the linked email. Writes from then on go to one place, the identifier their memory is kept under (primary in the answer); a forget of the person covers every identifier.

Call it from your server with your secret API key, and only with identifiers you have verified belong to the person: Graine never links identifiers from what someone says in a conversation. A linked phone number stops finding the person after 90 days with no conversation under it unless you send it again (numbers are reissued). An identifier that already belongs to another person is refused (409) and nothing changes.

Rate limit: 2000 requests per minute per organization, counted together with every endpoint that has no stricter limit of its own. Exceeding it returns 429 with Retry-After; the X-RateLimit-* response headers report your remaining allowance on every call.

POST
/v2/people/identifiers
/v2/people/identifiers

The Authorization access token

Authorization

Authorization
Required
Bearer <token>

Your Graine API key. Create one in the dashboard under Developers, or via POST /v2/api-keys. Send it as Authorization: Bearer <key>.

In: header

Request Body

application/jsonRequired

person
Required
Person

The person, by an identifier Graine already knows them by: the field your agents' Who is the user? setting names, or phone for callers.

addAdd

Identifiers to link to them (at most 20): a phone number, an email, your own user id. Only send identifiers you have verified belong to this person.

removeRemove

Identifiers to unlink from them (at most 20).

Response Body

200

The identifiers were linked or unlinked.

person
Required
PersonIdentityField

identifiers
Required
Identifiers

The person's identifiers after the change (empty when none are linked).

added
Required
Added

Identifiers newly linked.

removed
Required
Removed

Identifiers unlinked.

400

1000 — malformed or contradictory input. 1002 — a required parameter is missing.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

401

1100 — missing, unknown or inactive API key. 1101 — a browser session token was presented instead of an API key.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

403

1102 — the key is valid but lacks the scope this endpoint requires, or names another organization. GET /v2/scopes reports what a key holds.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

409

1201 — the resource's current state does not allow this action.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

422

1001 — the body or query failed validation; the message names the first offending field.

error
Required
integer

Stable integer code from the error table. Branch on this, not on the message.

message
Required
string

One human-readable sentence. Wording may change; the code will not.

429

1300 — the per-organization request rate or concurrent-call limit was reached. Carries Retry-After.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

503

1501 — a service this endpoint depends on is unreachable or returned a 5xx.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

curl -X POST "https://api.graine.ai/v2/people/identifiers" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "person": {
      "field": "user_id",
      "value": "cust-42"
    },
    "add": [
      {
        "field": "user_id",
        "value": "cust-42"
      }
    ],
    "remove": [
      {
        "field": "user_id",
        "value": "cust-42"
      }
    ]
  }'

The identifiers were linked or unlinked.

{
  "person": {
    "field": "user_id"
  },
  "identifiers": [
    {
      "id": "lnk_3f9a1c0b2d4e5f60718a",
      "field": "phone",
      "primary": false,
      "source": "api",
      "linked_at": "2026-10-29T10:00:00Z",
      "verified_at": "2026-10-29T10:00:00Z"
    }
  ],
  "added": 1,
  "removed": 0
}