For the complete documentation index, see llms.txt. This page is also available as Markdown.

Users Data

Field reference, snapshot semantics, and examples for sending user lists to Harmony

A users push tells Harmony who has access to an application. It answers questions like "who holds a paid seat", "who still has an account after leaving", and "which roles are granted where".

This page covers the users endpoint in full. For setup, see Bring Your Own App.

The most important rule: a push is a snapshot

Every users push is a complete replacement of the application's user list — not a list of changes.

Harmony compares each push against what it already knows and makes reality match your push. Users present in your push are created or updated. Users absent from your push are removed from Harmony.

Push 1:  alice, bob, carol      →  Harmony shows: alice, bob, carol
Push 2:  alice, carol           →  Harmony shows: alice, carol      (bob removed)
Push 3:  alice, bob, carol      →  Harmony shows: alice, bob, carol (bob restored)

This is what makes offboarding work — when someone loses access in the application, they disappear from your next push and Harmony reflects that automatically, with no delete call required.

Endpoint

POST https://external.harmony.io/custom-push/v1/users
Authorization: Bearer <access key>
Content-Type: application/json

Request body

Field
Type
Required
Description

external_app_id

string

Yes

The App ID you registered in Harmony. 1–200 characters, A–Z a–z 0–9 . _ -. Must be identical in every push for this application.

users

array

Yes

Between 1 and 100 user objects. See below.

snapshot_token

string

No

Only used when a single user list spans more than one request. See Sending more than 100 users.

schema_version

string

No

Defaults to "1.0". Reserved for future versions of this API.

User fields

Each object in the users array describes one account in the application.

Field
Type
Required
Limit
Description

external_id

string

Yes

1–255 chars

The application's own identifier for this account. Use whatever the application calls its user ID — a UUID, a numeric ID, a username. It identifies the row across pushes, so it must be stable for a given person.

email

string

Yes

Valid email, max 254 chars

The user's email address. Harmony uses this to match the account to an employee record, which is what links this application to the rest of your data. Accounts without a usable email address cannot be matched and are not retained.

name

string

No

255 chars

Display name, shown in Harmony's user lists. If omitted, Harmony shows the email address instead.

status

string

No

See values below

The account's state in the application. Defaults to active.

role

string

No

255 chars

The role this user holds, in the application's own vocabularyBilling Admin, Editor, read-only. Do not translate it into Harmony terms; access reviews are more useful when they show what the application actually says.

license_tier

string

No

paid, free, unknown

Whether this account consumes a billable seat. Omit if you genuinely do not know — do not guess.

plan_name

string

No

255 chars

The plan or SKU name attached to this user, for example Enterprise or Business Plus.

metadata

object

No

1 KB serialized

Any additional key/value data you want to carry along. Free-form JSON.

status values

Value
Meaning

active

The account is in normal use. This is the default.

inactive

The account exists but is deactivated or dormant.

pending

The account is invited or provisioned but not yet accepted.

suspended

The account is temporarily blocked by an administrator.

expired

The account's access has lapsed.

Reporting a user as inactive is not the same as omitting them. An inactive user still appears in Harmony, still counts toward the application's user list, and still shows up in access reviews — which is usually what you want, since a dormant account is still an account. Omitting a user removes them entirely.

license_tier values

Value
Meaning

paid

The account consumes a billable seat.

free

The account is on a free or included tier.

unknown

The tier is not determinable from the application's data.

Reporting license_tier is what makes license optimization possible — Harmony can only tell you about wasted spend if it knows which seats cost money.

Response

202 Accepted:

Field
Description

batch_id

A unique identifier for this request. Useful when contacting support about a specific push.

snapshot_id

The identifier of the user list this push opened or contributed to. You only need it when sending more than 100 users.

accepted_rows

How many user rows were accepted.

For error responses, see the API reference.

Examples

A minimal push

Only the two required fields per user:

A fully populated push

Every field in use:

A complete sync script

Note the guard before pushing. If your application's API returns an empty list because of an outage or an expired credential, pushing that empty result would remove every user from Harmony. A check like this costs nothing and prevents the worst possible outcome.

Sending more than 100 users

A single request carries at most 100 users. For larger applications, split the list across several requests that Harmony joins into one user list.

  1. First request — send the first 100 users and omit snapshot_token. Harmony opens a new user list and returns its snapshot_id.

  2. Every following request — send the next 100 users and set snapshot_token to the snapshot_id you received from the first request.

  3. When the last request succeeds, the list is complete and replaces the previous one.

Rules for multi-batch pushes:

  • snapshot_token must be a value Harmony gave you. You cannot invent one.

  • Complete the full sequence within an hour. A user list left half-sent for longer is rejected when you try to continue it, which leaves it permanently incomplete.

  • Send each user exactly once across the whole sequence. Sending the same user twice under one list inflates seat counts until the next clean push.

Large directories. The one-hour window covers the whole sequence, not each request. A sequential loop is fine for most directories; for very large ones, send several requests concurrently so the sequence finishes comfortably inside the window. Requests are rate limited, so ramp up gradually rather than firing everything at once — a 429 means slow down, not stop.

Push whenever the application's user list changes, or on a fixed schedule if you cannot detect changes. Daily is a good default. Pushing more often is safe — each push simply replaces the previous list.

There is no penalty for pushing an unchanged list.

See also

  • Usage data — reporting what users actually did

  • API reference — errors, retries, and limits

Last updated

Was this helpful?