unPLUGDevelopers

Members API

Create a member

POST/v1/members

Enrolls a guest. Call it when someone signs up in your app, or the first time an existing account of yours opens the rewards screen. It is safe to call again for a guest you already enrolled: the same external_id returns the existing member.

Permissions: Secret key with members:write.

Request headers#

  • Idempotency-KeystringRequired
    Required on this endpoint. Any string up to 255 characters; use a UUID v4. Missing returns 400 idempotency_key_required.
    Max Length 255

Request body#

  • external_idstringRequired
    Your id for this guest. Up to 128 characters, unique in your brand.
    Max Length 128
  • first_namestring
  • last_namestring
  • emailstring (email)
    Saved in lowercase.
  • phonestring
    E.164. See phone rules below.
  • phone_verifiedboolean
    Send true only if you confirmed the number with an SMS code. Default false.
  • birthdaystring (date)
    YYYY-MM-DD.
  • communication_preferencesobject
    email_marketing, sms_marketing, push_marketing. Send what the guest agreed to at sign-up.
    Show attributesHide attributes
    • email_marketingboolean
    • sms_marketingboolean
    • push_marketingboolean
  • metadataobject
    Up to 20 keys, 500 characters each.

Response fields#

Returns 201 or 200 with Member

  • idstring (uuid)
    unPLUG's id for the member. Store it next to your user record.
  • external_idstringNullable
    Your id for the guest, up to 128 characters. null for a guest who has only earned at the register and isn't linked to your login yet.
    Max Length 128
  • statusstring
    active. The member.deleted webhook carries deleted; after that, calls about the member return 410 member_deleted.
    One of active, deleted
  • first_namestringNullable
  • last_namestringNullable
  • emailstring (email)Nullable
    Saved in lowercase.
  • phonestringNullable
    E.164, for example +15125550142.
  • phone_verifiedboolean
    true when you confirmed the guest owns the number, for example with an SMS code. Only verified phones link to existing members.
  • birthdaystring (date)Nullable
    YYYY-MM-DD.
  • points_balanceinteger
    Points the member has now. Never below zero.
  • lifetime_pointsinteger
    All points ever earned, used for tiers. Spending doesn't lower it.
  • id and name of the current tier.
    Show attributesTierRef
    • idstring (uuid)
    • namestring
  • next_tierobjectNullable
    id, name and points_needed (lifetime points still to earn). null at the top tier.
    Show attributesHide attributes
    • idstring (uuid)
    • namestring
    • points_neededinteger
  • communication_preferencesobject
    Marketing consent: email_marketing, sms_marketing, push_marketing. See communication preferences.
    Show attributesHide attributes
    • email_marketingboolean
    • sms_marketingboolean
    • push_marketingboolean
  • metadataobject
    Your own string values. Up to 20 keys, 500 characters each. Don't put personal data here.
  • linked_existingboolean
    Only on create: true when an existing member was linked by verified phone.
  • enrolled_atstring (date-time)
    When the guest joined the program.
  • created_atstring (date-time)
  • updated_atstring (date-time)

Which response you get#

SituationStatusWhat happens
New external_id, no phone match201A new member is created.
external_id already exists200The existing member is returned unchanged. Use PATCH to change their details.
Verified phone matches a member with no external_id200That member is linked to your external_id and returned with "linked_existing": true. Their points, tier and history stay.
Phone belongs to another member who has an external_id409phone_in_use. Nothing is created.

Phone rules#

  • Verified phones link. A guest who earned at the register before downloading your app already has a member under their phone number. Send phone_verified: true and they keep those points.
  • Unverified phones never link. They create a new member and the phone is saved with phone_verified: false. This stops someone from typing another guest's number to take their points.
  • One phone per linked member. If a member with an external_id already has the number, you get 409 phone_in_use. Ask the guest to sign in to their existing account, or create the member without the phone.
  • Sandbox test numbers +15005550100 to +15005550199 count as verified in the sandbox.

Maya has been earning at the South Congress register under +15125550142 since June 2025, so the same request finds that member, links it to usr_10482 and returns it:

Response200
{
  "id": "3f2b8c1e-6d0a-4e7b-9f3c-2a1d5e8b7c40",
  "external_id": "usr_10482",
  "phone": "+15125550142",
  "phone_verified": true,
  "points_balance": 420,
  "lifetime_points": 1880,
  "enrolled_at": "2025-06-14T15:02:44Z",
  "linked_existing": true
}

The response above is trimmed. The full response is a member object.

Error descriptions#

400Bad request
idempotency_key_required

The Idempotency-Key header is missing.

400Bad request
missing_param

external_id is missing.

400Bad request
invalid_param

A field has the wrong format, for example a phone that isn't E.164 or more than 20 metadata keys. param names the field.

409Conflict
phone_in_use

Another member with an external_id has this phone.

409Conflict
request_in_progress

A request with this Idempotency-Key is still running. Retry after a second.

422Unprocessable
idempotency_key_reused

This key was used with a different body.

Any endpoint can also return the common errors.