Skip to content

Profile page (web) ​

The signed-in customer's own page: who they are, their points and level, and the settings they can change. It is one page rather than a journey, so it has no player. The tables list every call it integrates, grouped by what the page is doing.

Loading the page ​

SectionAPI callAccess
Name, email, phone, avatar, username, bioGET /api/v1/user/detailOrigin + Brand key + Customer
Points and levelThe same call — user_points and brand_level
Referral linkThe same call — referral_link
Points historyGET /api/v1/user/loyalty/point_transactionOrigin + Brand key + Customer
Saved addressesGET /api/v1/user/addressOrigin + Brand key + Customer
Notification preferencesGET /api/v1/user/preferencesOrigin + Brand key + Customer
Order historyGET /api/v1/user/ordersOrigin + Customer
CollectionSee the collectible page

GET /api/v1/user/detail returns most of the page in one response:

  • user_points is folded into one object: total, points_earned and total_order, plus one key per brand holding that brand's balance.
  • brand_level is the customer's tier, with its thresholds and wallet_image.
  • total_trades counts completed trades in both directions.
  • addresses, user_documents and shopify_gift_cards (codes decrypted) are included.

user_points, brand_level and referral_link are deleted from the response when the customer is not a loyalty user (isLoyaltyUser false). The page has to treat them as optional. The call also only finds a verified account. An account that has registered but not verified its OTP gets User not found, even with a valid token.

Editing the page ​

ActionAPI callAccess
Save name, email, phone, birthday, gender, bioPUT /api/v1/user/details/updateOrigin + Brand key + Customer
Check a username before saving itGET /api/v1/user/available/username?username=Origin + Customer + Brand key
Upload an avatarPUT /api/v1/user/uploadImage (multipart), then send result.url as user_profileOrigin + Brand key + Customer
Add / edit / remove an addressPOST /api/v1/user/address/add, PUT …/update/:addressId, DELETE …/delete/:addressIdOrigin + Brand key + Customer
Change a notification preferencePUT /api/v1/user/preferenceOrigin + Brand key + Customer
Change the passwordThe password reset flow — not details/update, see belowAs that flow states
Close the accountGET /api/v1/user/deactivate sends an OTP, then POST /api/v1/user/deactivate/confirmation with otpOrigin + Brand key + Customer

What the API forces onto this page ​

  • Never send password to details/update. The validator accepts it, but the update writes the value without hashing it. Password login compares against an argon2 or SHA-256 hash, so the customer's password stops working. Offer password changes through the reset flow.
  • Replace the stored token after every save. details/update returns a new token, because the customer token carries the email, phone, names, avatar, bio and username. If the page keeps the old token, those claims stay stale.
  • Email and phone changes are not re-verified. The update refuses one already used by another verified customer of the brand (Email or PhoneNumber is already taken.). Otherwise it saves it directly, with no OTP. An email containing + is refused.
  • Check the username first. The update does not check whether a username is taken. The column is unique, so a taken username fails as a database error rather than a readable message. available/username checks across all brands, because the uniqueness does too.
  • Upload with PUT, not POST. PUT /api/v1/user/uploadImage stores the file on Cloudinary and returns a public url, which is what user_profile holds. The POST on the same path stores a private /api/v1/files/ link meant for receipts and IDs. The PUT replies with status: true, not success.
  • fullName follows the names. On every save, the customer record rebuilds fullName from the stored firstName and lastName. Sending fullName on its own has no effect on a customer who has either name. Edit the two name fields instead.
  • The primary address cannot be deleted. Make another address primary first.
  • Every save is a loyalty event. details/update logs a profile-update event with the changed field names. A profile-completion campaign can move on it, so the page should re-read campaign progress after saving. See Earn and spend.
  • open_to_trade and show_collections_for_trade are on this payload too. They are trading switches; the storefront has no trading calls.

Batch platform, Shopify app and API documentation