Customer profile, marketing consent, and payment methods
Read and update a customer's profile, capture marketing consent in a GDPR-defensible way, manage their labels, and work with the payment methods Trybe holds on file. This guide covers the two sides of the customer surface — back-office operations done with a personal access token, and self-service operations done with an authenticated customer's own token.
Before you start
- For back-office operations, a personal access token with permission to manage customers on the target site. See authentication for the header format.
- For self-service operations, a customer access token obtained through
the SSO flow. The self-service endpoints (
/customers/my-account/*and/shop/my-account/*) only respond to customer tokens — staff tokens are explicitly rejected. - A
Customerto operate on. Customers belong to a brand; the API rejects cross-brand operations. - A webhook configuration listening for
customer.created,customer.updated,customer.deleted, and the relatedcustomer_address.*,customer_labels.*, andcustomer_note.*events if you want to keep a downstream CRM in sync. See the webhooks guide.
The shape of the customer surface
The customer domain splits into two parallel API surfaces:
-
Back-office (
/customers/customers/{customerId}/...,/customers/labels,/customers/marketing-preferences,/customers/payment-methods). Use these with a personal access token whose user has the relevant permissions. The token acts on behalf of the operator, and permission checks are performed against the operator's role. -
Self-service (
/customers/my-account/...,/shop/my-account/...). These endpoints take the authenticated customer's bearer token and return only that customer's data. There is nocustomer_idpath parameter — the customer is implicit in the token.
Use the back-office surface for staff workflows and CRM imports; use
the self-service surface for the customer-facing storefront. Mixing
them up is the most common authentication mistake against this domain
— a back-office token on a self-service endpoint returns 401, and a
customer token on a back-office endpoint returns either 401 or 403
depending on the route.
1. Reading and updating the customer
Fetch a customer by ID with getCustomer:
curl "https://api.playground.try.be/customers/customers/$CUSTOMER_ID" \
-H "Authorization: Bearer $TRYBE_API_KEY" \
-H "Accept: application/json"
const res = await fetch(
`https://api.playground.try.be/customers/customers/${customerId}`,
{
headers: { Authorization: `Bearer ${process.env.TRYBE_API_KEY}` },
},
)
const { data: customer } = await res.json()
The response is the full Customer record — name, email, phone, date
of birth, gender, addresses, the brand they belong to, marketing
preferences (summary form), and timestamps. The brand attribution is
the most important field to keep in mind: a customer with the same
email on two different brands is two separate records, and the API
will not merge them.
Update with PUT:
curl "https://api.playground.try.be/customers/customers/$CUSTOMER_ID" \
-X PUT \
-H "Authorization: Bearer $TRYBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jane",
"last_name": "Doe",
"phone": "+447700900000"
}'
$response = Http::asJson()
->withToken(config('services.trybe.token'))
->put("https://api.playground.try.be/customers/customers/{$customerId}", [
'first_name' => 'Jane',
'last_name' => 'Doe',
'phone' => '+447700900000',
]);
updateCustomer is a full update — pass every field you want to keep,
not just the changed ones, unless your write strategy is genuinely
patch-style. The endpoint accepts partial bodies and merges, but the
server-side resolution of phone normalisation, address re-geocoding,
and label retention is easier to reason about when the body is
explicit.
The customer can also be deleted (anonymised); the record is kept for
accounting and reporting but PII is scrubbed. See
getCustomer,
updateCustomer, and
deleteCustomer.
2. Self-service: My Account
For storefront flows where the customer is signed in via SSO and is
managing their own profile, switch to the my-account surface. The
authenticated customer is implicit, so no customer_id is sent.
Profile summary
curl https://api.playground.try.be/customers/my-account \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Accept: application/json"
Returns the same Customer payload as getCustomer for the
authenticated customer. See
getMyAccountDetails.
Order history
curl https://api.playground.try.be/shop/my-account/orders \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Accept: application/json"
Returns the customer's submitted-and-settled orders — completed
baskets with item details — for the "My Bookings" screen. See
listMyAccountOrders.
Memberships, credits, charges
The same pattern applies for the customer's memberships, credit balance, and membership charge history:
curl https://api.playground.try.be/customers/my-account/memberships \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
curl https://api.playground.try.be/customers/my-account/credits \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
curl https://api.playground.try.be/customers/my-account/charges \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
See
listMyAccountMemberships,
listMyAccountCredits, and
listMyAccountCharges.
These four endpoints (orders, memberships, credits, charges) are the backbone of the customer self-service area. Wire them up in a tabbed "My Account" page and you've covered most of what a customer wants to see.
3. Labels
Labels are ad-hoc tags attached to customers for segmentation — "VIP", "Local", "Bridal party", "Returned in 2025". They're managed at the organisation level and applied at the customer level.
Manage the catalogue
curl https://api.playground.try.be/customers/labels \
-H "Authorization: Bearer $TRYBE_API_KEY"
curl https://api.playground.try.be/customers/labels \
-X POST \
-H "Authorization: Bearer $TRYBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "VIP", "colour": "#9999ff" }'
curl "https://api.playground.try.be/customers/labels/$LABEL_ID" \
-X PUT \
-H "Authorization: Bearer $TRYBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "VIP guests" }'
Labels are soft-deleted, not hard-deleted — deleteLabel archives the
label and removes it from the active picker; restoreLabel brings it
back, complete with its prior attachments. The webhook events
customer_labels.added and customer_labels.removed carry the full
label data so downstream systems can build their own segmentation
views.
See listLabels,
createLabel,
updateLabel,
deleteLabel, and
restoreLabel.
Attach to a customer
Label attachments live on the customer's record (a customer_labels
collection) and are managed through the customer-scoped label routes
exposed at /customers/customers/{customerId}/labels. Subscribe to
customer_labels.added / customer_labels.removed for asynchronous
notification.
4. Marketing consent
This is the area where getting the API right matters most for GDPR compliance. Three things have to be true:
- Explicit opt-in. Consent is granted by the customer through an affirmative action, not by pre-ticked boxes or "by booking you consent to..." clauses.
- Auditable record. The platform records when and by which mechanism each opt-in was granted, so you can demonstrate compliance if asked.
- Easy opt-out. The customer can opt out at any time, and the opt-out takes effect immediately.
The API supports all three. The data model has two layers: the marketing preferences themselves (the channels and topics — "Email newsletter", "SMS offers", etc., configured per organisation), and the opt-ins (the customer-level grants against each preference).
Manage the catalogue
curl https://api.playground.try.be/customers/marketing-preferences \
-H "Authorization: Bearer $TRYBE_API_KEY"
curl "https://api.playground.try.be/customers/marketing-preferences/$PREF_ID" \
-H "Authorization: Bearer $TRYBE_API_KEY"
curl "https://api.playground.try.be/customers/marketing-preferences/$PREF_ID" \
-X PUT \
-H "Authorization: Bearer $TRYBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Monthly newsletter", "is_active": true }'
See
listMarketingPreferences,
getMarketingPreference, and
updateMarketingPreference.
Capture consent (self-service)
The customer-facing opt-in / opt-out lives on the my-account surface:
curl "https://api.playground.try.be/customers/my-account/marketing-preferences/$PREF_ID" \
-X POST \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
curl "https://api.playground.try.be/customers/my-account/marketing-preferences/$PREF_ID" \
-X DELETE \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
async function setConsent(prefId, optedIn) {
const url = `https://api.playground.try.be/customers/my-account/marketing-preferences/${prefId}`
const res = await fetch(url, {
method: optedIn ? 'POST' : 'DELETE',
headers: { Authorization: `Bearer ${customerToken}` },
})
if (!res.ok) throw new Error('Failed to update consent')
return res.json()
}
The opt-in is recorded with a timestamp and a source (the my-account
endpoint, the basket flow, or a back-office manual change) so the
provenance is auditable. See
actionMyAccountMarketingPreferenceOptIn
and
actionMyAccountMarketingPreferenceOptOut.
Subscribe to marketing_preference_opt_in.updated (see the
webhooks guide) to keep your downstream
marketing-automation systems in sync with the source-of-truth state.
5. Payment methods
Payment methods in Trybe are tokenised references to cards or mandates held by the underlying processor (Stripe, GoCardless, etc.). The platform never sees the raw PAN, IBAN, or expiry; only the token and a non-sensitive summary (last 4 digits, brand, country).
Back-office listing
curl "https://api.playground.try.be/customers/payment-methods?customer_id=$CUSTOMER_ID" \
-H "Authorization: Bearer $TRYBE_API_KEY"
Filter by customer_id, type, processor, status,
membership_payment_method (boolean), or for_barcode. The result is
paginated and ordered by creation date. See
listPaymentMethods.
Self-service listing
curl https://api.playground.try.be/customers/my-account/payment-methods \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
Returns the customer's saved methods. See
listMyAccountPaymentMethods.
Deletion
curl "https://api.playground.try.be/customers/payment-methods/$PAYMENT_METHOD_ID" \
-X DELETE \
-H "Authorization: Bearer $TRYBE_API_KEY"
Deletion is a soft detach — the underlying processor token is revoked
and the method is no longer offered to the customer. See
deletePaymentMethod.
Adding a method
There is no createPaymentMethod endpoint, by design. New methods are
captured as a side-effect of taking a payment through the basket flow
or signing a direct-debit mandate through the memberships flow.
The processor's hosted Checkout page (Stripe Checkout, GoCardless
Checkout) is responsible for capturing the bank or card details and
tokenising them; Trybe receives the token and stores the method
record. Build your "add a new card" UX as a basket-driven flow with a
zero-value reserve or a small refundable hold, not as a standalone
form.
6. Subscribing to outcomes
The customer domain is rich with webhook events. The ones most integrations care about:
customer.created,customer.updated,customer.deleted— the basic CRUD events.datais aCustomershape (or the deleted ID).customer_address.created,customer_address.updated,customer_address.deleted— address-level changes.customer_labels.added,customer_labels.removed— label attachments.customer_note.created,customer_note.updated,customer_note.deleted— operator notes attached to the customer record.marketing_preference_opt_in.updated— the moment of truth for marketing consent. Subscribe to this and use it (not thecustomer.updatedevent) to drive your marketing-automation audience membership.
All of these are documented in the webhooks guide.
Going further
- Single Sign On — the OAuth + OpenID flow that produces the customer access tokens used on the my-account endpoints.
- Build a basket and check out — the flow that creates and updates customer records as a side effect of guest-checkout submission.
- Manage memberships — the membership lifecycle bound to a customer record.
- Endpoint references:
getCustomer,updateCustomer,getMyAccountDetails,listMyAccountOrders,listMarketingPreferences,listPaymentMethods.
Production checklist
- Scope tokens correctly. A personal access token is a back-office credential; a customer access token from the SSO flow is the customer's own credential. Never use a PAT on a my-account endpoint or a customer token on a back-office endpoint. Keep them in separate variables in your code so the type confusion can't happen by accident.
- Audit-log every customer write. The webhook events give you the what; your own application logs should give you the who. Log the staff user and the request ID against every write you make with a PAT, so you can answer "who changed this customer's address last Tuesday?" without going back to the platform.
- Treat marketing consent as the source of truth. Don't store a
"subscribed?" boolean in your own database — store an audit trail
of the opt-in events and treat the latest one as authoritative. The
marketing_preference_opt_in.updatedwebhook gives you the granularity you need. - Handle GDPR data-subject requests via the platform. For
deletion requests, use
deleteCustomerto anonymise the record rather thanDELETEagainst your own database. The platform retains the anonymised record for accounting purposes (orders, tax) and zeros out the PII; your own application should follow suit. - Don't store card details client-side. The platform never sees raw PANs; nor should you. Capture cards via Stripe Checkout (or whichever processor the site is configured with) and rely on Trybe's tokenised method record as the durable reference.
- Verify webhook signatures. Customer-domain events carry PII; unverified deliveries could be forged. Compute the SHA-256 HMAC using your configured secret and reject mis-signed deliveries.
- Respect the brand boundary. A
customer_idfrom one brand cannot be used in operations scoped to another brand. If your integration covers multiple brands, namespace your downstream data accordingly — don't merge customers across brands without the customer's explicit consent and a clear linking record. - Surface consent state on every customer-facing form. When asking the customer for information that would be used for marketing — phone number, email, postcode — show the current consent state and let them opt in or out in line. Bury it in a separate "settings" tab at your peril.
- Retry only reads on
5xx. Customer reads (getCustomer,listLabels) are safe to retry with exponential backoff. Writes aren't — an unconditional retry ofupdateCustomerafter a502could overwrite a concurrent change. Re-fetch first and reconcile.