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

Use Case: Marketing Email/SMS Consent

Collect and manage customer consent for marketing email and SMS through the PodPlay API while respecting tenant configuration and customer choice.

Overview

Marketing consent records whether a customer agrees to receive promotional email or SMS messages from a club. These preferences do not control transactional messages such as booking confirmations, receipts, login codes, or password resets.

PodPlay stores email and SMS consent separately:

  • emailMarketingOptIn

  • smsMarketingOptIn

Each preference also has a last-changed timestamp. Integrators should collect a separate, explicit choice for each enabled channel and must not silently opt customers in.

Authentication & Authorization

Server-to-server integrations should authenticate with an API key:

x-api-key: <write-capable-api-key>

An API key is authenticated as its associated PodPlay user and has the same authorization as that user. It does not grant a special marketing-consent privilege of its own.

  • A customer session can read and update that customer's own preferences.

  • A write-capable API key whose associated user is a tenant Admin can read and update another customer's preferences.

  • A read-only API key cannot create a customer or update preferences; writes return 403 Forbidden.

  • A key associated with a user who has no authority over the target customer also returns 403 Forbidden.

  • Creating or issuing API keys is a PodPlay Admin operation. A tenant Admin can hold a key, but cannot mint one.

Tenant Configuration Discovery

Tenant settings tell an integration whether to render a consent choice and what copy to show. They do not record customer consent, and they do not supply a default opt-in value for users created through POST /users.

Before showing consent choices, read:

The relevant settings are:

Setting ID
Purpose

company.emailMarketingOptIn

Determines whether the email marketing consent channel is enabled

company.smsMarketingOptIn

Determines whether the SMS marketing consent channel is enabled

company.emailMarketingOptInDefault

Used only by PodPlay's signup UI to set the initial Email checkbox state; it is not an API consent default and does not establish customer consent

company.emailMarketingOptInText

Tenant-configured customer-facing email consent copy

company.smsMarketingOptInText

Tenant-configured customer-facing SMS consent copy

There is no SMS equivalent of company.emailMarketingOptInDefault.

The response is a collection whose items contain id and value. Use company.emailMarketingOptIn and company.smsMarketingOptIn to decide which choices to display, and show company.emailMarketingOptInText / company.smsMarketingOptInText as the matching customer-facing copy.

Do not treat any tenant setting as proof of customer consent. company.emailMarketingOptInDefault never applies to API-created users and does not change stored preferences when a marketing field is omitted from POST /users.

Do not change tenant-wide marketing settings as part of a customer signup or preference-management workflow. Tenant configuration is managed separately by authorized PodPlay staff.

  1. Read the tenant settings.

  2. Show only enabled consent channels.

  3. Display the tenant-configured consent text for each channel.

  4. Present separate, explicit choices for email and SMS.

  5. Submit the customer's selected booleans when creating the account.

  6. Store the returned customer ID.

  7. For later changes, let the customer manage their own preferences where possible. Otherwise, update only after an explicit customer request and with authorization valid for that customer record.

  8. Read the preferences when displaying or reconciling the current state.

Example — Create a Customer With Explicit Choices

Both marketing fields are optional booleans.

Omitting emailMarketingOptIn and/or smsMarketingOptIn does not apply a tenant-level marketing-consent default. PodPlay stores an omitted field as false, and the corresponding emailMarketingOptInUpdatedAt or smsMarketingOptInUpdatedAt timestamp remains unset. Sending false explicitly also stores false, but records that timestamp because it is a submitted choice. company.emailMarketingOptInDefault does not affect API-created users.

When the associated API-key user is authorized to create customers, PodPlay creates the customer and initializes marketing preferences from any submitted booleans. Fields that were omitted are stored as false without a last-changed timestamp. Use a unique disposable address when testing in a sandbox. Account creation still depends on Firebase user creation; a 422 from POST /users can mean a signup-service failure rather than a consent-validation failure.

Customer-app sign-in (password, passwordless, OTP, or social) can also create an account and record consent at that moment. That is a browser/session flow, not this API-key integration, and it is out of scope for this guide. After the customer exists, use GET/PATCH /users/{userId}/preferences as below.

Read Current Preferences

Example response:

The emailMarketingOptInUpdatedAt and smsMarketingOptInUpdatedAt fields record when each value last changed. A timestamp can be absent when that channel has never received an explicit value.

Update a Preference

The marketing fields are optional booleans, so send only the preference the customer asked to change.

Example — Opt Out of Email Marketing

A successful request returns 200 OK with the complete preferences object. When the value changes, PodPlay updates that channel's timestamp and sends marketing_preferences_updated to Segment-connected marketing tools.

After a write, read the preferences again when the integration needs to confirm or reconcile the persisted state.

Disabled Channel Behavior

If the matching tenant channel is disabled, PodPlay removes that field from the update before saving. The request can still return 200 OK, but the preference and timestamp remain unchanged. Treat the returned response as the source of truth rather than assuming the submitted value was accepted.

The phone-verification flow can accept smsMarketingOptIn at:

Use that field only while completing the API's phone-number verification flow. For a later standalone SMS consent change, use:

This keeps general preference changes in the endpoint that applies tenant-channel gating, updates the consent timestamp, and emits the marketing preference event.

Do

  • Read tenant settings before rendering consent choices.

  • Show only enabled channels and their configured consent text.

  • Keep email and SMS choices separate.

  • Record the customer's explicit selection during signup.

  • Honor opt-outs immediately.

  • Use the returned preference state and timestamps for reconciliation.

  • Use sandbox-only customers and credentials while testing.

Do Not

  • Do not silently opt a customer in.

  • Do not interpret tenant settings (including company.emailMarketingOptInDefault) as proof of consent or as a default opt-in for API-created users.

  • Do not send a consent value for a channel the tenant has disabled.

  • Do not update another customer without explicit instruction and valid authorization.

  • Do not expose API keys in browser code, logs, examples, or documentation.

  • Do not use the phone-verification endpoint as a general-purpose preferences endpoint.

Practical Integrator Scenario

An external booking or signup experience creates a new customer. Before submission, it fetches tenant settings, conditionally renders separate email and SMS consent checkboxes with the configured text, and creates the customer with the selected values.

Later, the experience reads the customer's preferences to display the current state. It directs the customer to manage changes through their own authenticated preferences whenever possible. If the integration performs a requested change, it uses authorization valid for that customer record, patches only the requested field, and confirms the returned state.

Troubleshooting

Result
Meaning and next step

200 OK, but the submitted value is unchanged

The marketing channel may be disabled. Re-read tenant settings and use the returned preference as the source of truth.

403 Forbidden

The API key is read-only, or its associated user lacks authority over the target customer. A tenant Admin write key is expected to succeed; a customer-scoped or read-only key is not. Do not retry with broader credentials automatically.

404 Not Found

The customer ID is invalid, or no preferences record exists for that customer. Create the customer first, or confirm that signup finished creating preferences.

422 Unprocessable Entity during signup

Review structured validation errors when present. A generic signup failure can also mean the account-creation service is unavailable.

Marketing Preferences API — Technical Specification

For the complete request and response schemas, refer to the API specification:

get
Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Path parameters
userIdstringRequiredExample: current
Responses
200

Get the user preferences

No content

get/users/{userId}/preferences
GET /apis/v2/users/{userId}/preferences HTTP/1.1
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
200

Get the user preferences

No content

patch
Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Path parameters
userIdstringRequiredExample: current
Body
showUserNameOnEventsbooleanRequired
showUserRatingOnEventsbooleanRequired
chatOptInbooleanRequired
emailMarketingOptInbooleanRequired
smsMarketingOptInbooleanRequired
Responses
200

Update the user preferences

No content

patch/users/{userId}/preferences
PATCH /apis/v2/users/{userId}/preferences HTTP/1.1
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 128

{
  "showUserNameOnEvents": true,
  "showUserRatingOnEvents": true,
  "chatOptIn": true,
  "emailMarketingOptIn": true,
  "smsMarketingOptIn": true
}
200

Update the user preferences

No content

Last updated

Was this helpful?