Guides

Staff & contacts

Sync the people at a merchant, the owner and staff users, as contacts.

The Partner API tells you a shop installed your app, but nothing about the people in it. On install you only ever have the account owner; staff members only become visible to your app as they use it. This endpoint lets you push those people to PartnerConsole, where they appear as contacts on the customer, usable in flows and campaigns.

Getting the people from Shopify

Shopify only reveals a staff member's name and email through a token exchange for an online access token, which returns an associated_user:

  • Embedded apps: exchange the App Bridge id_token for an online token; read associated_user.
  • Non-embedded apps: request an online access token during OAuth; the grant response carries associated_user.

Either way you end up with { id, first_name, last_name, email, email_verified, account_owner, locale }. That's what you forward to us.

There is no "list all staff" for a standard app, that needs the read_users scope (Shopify Plus only). So you capture staff incrementally, one per session as each person opens your app. The owner/installer you get on install; the rest accrue over time. This is a Shopify constraint, every app faces it.

You own the data, or we do — your choice

The endpoint is built so either model works, with no change on our side:

  • You store staff in your own system and sync to us. Keep your own table, push the full roster whenever it changes with reconcile: true (we add present people and remove absent ones, so deletes propagate).
  • You send straight to us and don't store anything. Fire each staff member as you see them (default upsert), and read them back with /customer if you need them. We become your system of record.

Both converge to the same state because we dedupe on the Shopify user id (id), not email, so re-sending the same person is always safe.

Send one, or the whole roster

# Incremental: one person, fire-and-forget per session
curl -X POST https://api.partnerconsole.co/v1/staff \
  -H "X-Api-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{
    "myshopifyDomain": "example.myshopify.com",
    "staff": [{
      "id": "gid://shopify/StaffMember/123",
      "firstName": "Ada", "lastName": "Lovelace",
      "email": "[email protected]", "accountOwner": true, "installer": true
    }]
  }'
# Full reconcile: your complete roster; anyone not listed is removed
curl -X POST https://api.partnerconsole.co/v1/staff \
  -H "X-Api-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{
    "myshopifyDomain": "example.myshopify.com",
    "reconcile": true,
    "staff": [ {"id": "…", "email": "[email protected]"}, {"id": "…", "email": "[email protected]"} ]
  }'

How they appear

  • Each staff member becomes a contact on the customer, keyed on the Shopify user id, with a role derived from accountOwner (owner) / installer and tags you send.
  • Contacts a human added by hand in the console are marked manual and are never touched by a reconcile, only app-sourced contacts are reconciled.
  • email can change; because we key on the stable user id, a renamed email updates the same contact instead of creating a duplicate.

When to call it

  • On install, with the owner/installer flagged.
  • On each embedded page load (or online-token refresh) for the current user, cheap and idempotent.
  • On a schedule with reconcile: true if you maintain your own roster and want deletes to propagate.

On this page