Pulse CRM
The retention brain: an encrypted identity vault, per-channel consent, first-class responsible-gaming state, and a PII-free Player 360 profile computed from the events you already send. Campaigns and automations build on this foundation.
Identity & consent (the vault)
PUT /v1/crm/players/{player_id}/identity
{"email": "player@example.com", "first_name": "Sam", "birthday": "1990-04-12",
"email_status": "subscribed", "rg_status": "ok"}
-> {..., "messageable": {"email": true, "sms": false}, "erased": false}- Ciphertext at rest. Contact fields are encrypted before storage; the database never holds plaintext, and audit logs record field names, never values.
- Merge-writes. Send only what changed — an unsubscribe webhook PUTs one field.
- RG is first-class.
self_excluded/cooloffblocks every channel, and — deliberately — survives erasure. - Erasure.
DELETE .../identitywipes PII + consent and tombstones (reads return 410); re-ingest requiresreconsent: true.
The Player 360 profile (PII-free)
GET /v1/crm/players/{player_id}/profile
-> {"ltv": 84500, "purchase_count": 12, "days_since_purchase": 3,
"wagered_30d": 220000, "streak_len": 9,
"churn_band": "active", // active | cooling | at_risk | dormant | never_seen
"vip_tier": "Gold", "days_to_birthday": 41,
"messageable": {"email": true, "sms": false}, "rg_status": "ok"}Computed from the event stream — reserved types purchase (LTV, recency), wager/win (play, GGR), plus streak and VIP state. Safe to render in your back-office: player ids and aggregates only.
messageable is computed from consent + RG + erasure, and every future Pulse campaign send must pass it. Suppressed players can never appear in an audience or an export.Endpoint summary
| Endpoint | Purpose | Billable |
|---|---|---|
PUT /v1/crm/players/{id}/identity | push identity / consent / RG | no |
GET /v1/crm/players/{id}/identity | read identity + messageable | no |
DELETE /v1/crm/players/{id}/identity | right-to-erasure | no |
GET /v1/crm/players/{id}/profile | Player 360 (PII-free) | no |
Coming next on this foundation: audience builder, campaign promo minting with export to your marketing tools, and self-driving retention automations. The docs will grow as each ships.
Integrate with your coding agent
Building with Claude, Cursor, Copilot, or another AI agent? Paste this prompt — it contains the complete contract, the security rules, and an acceptance checklist, so your agent can implement the integration without reading these docs.
Integrate the Pulse CRM foundation into this codebase: identity sync,
consent, responsible-gaming state, and the Player 360 profile. Pulse is a
gamification API for sweepstakes sites. Follow this architecture exactly -
it is a hard security contract.
## Non-negotiable rules
1. PULSE_API_KEY is backend-only. All calls go our backend -> Pulse.
2. PII flows ONE way: we push contact data to Pulse's encrypted vault.
Profile reads are PII-free (ids + aggregates) and safe for back-office UI.
3. Responsible-gaming state MUST be pushed on change (self-exclusion,
cool-off). It blocks all Pulse messaging and survives erasure.
4. Honor deletion: when a player invokes erasure with us, call Pulse's
DELETE too. Re-ingest after erasure requires reconsent: true.
## Pulse API (base https://api.playwithpulse.com)
- PUT /v1/crm/players/{player_id}/identity (merge-write; send only
changed fields)
{"email"?, "first_name"?, "phone"?, "birthday"? ("YYYY-MM-DD"|"MM-DD"),
"email_status"?: "none"|"subscribed"|"unsubscribed",
"sms_status"?, "rg_status"?: "ok"|"cooloff"|"self_excluded",
"rg_until"? (ISO, cooloff only), "reconsent"?: bool}
-> identity + "messageable": {"email": bool, "sms": bool}
- DELETE /v1/crm/players/{player_id}/identity (erasure; 410 afterwards)
- GET /v1/crm/players/{player_id}/profile (PII-free)
-> {ltv, purchase_count, last_purchase_at, days_since_purchase,
wagered_30d, streak_len, churn_band, vip_tier, days_to_birthday,
has_identity, messageable, rg_status, first_seen, last_seen}
- POST /v1/events with reserved types: "purchase" (value = amount,
idempotency_key = order id), "wager", "win".
## Build these pieces
A. On signup and on profile update: PUT identity with email + consent
states (+ birthday if we hold it). On unsubscribe webhooks: PUT just
{"email_status": "unsubscribed"}.
B. On RG changes (self-exclusion, cool-off) in OUR system: PUT rg_status
immediately - this is a compliance path, treat failures as alerts.
C. On account deletion: DELETE the Pulse identity in the same flow.
D. On purchase completion: POST the purchase event (idempotent by order id).
E. (Optional, recommended) A "Player 360" panel in OUR back-office that
renders GET .../profile for support staff - it is PII-free by design.
## Acceptance checklist
- [ ] Identity round-trips; unsubscribes flip messageable.email to false.
- [ ] Setting rg_status=self_excluded makes messageable all-false.
- [ ] After DELETE, GET returns 410; re-PUT without reconsent is 410.
- [ ] A purchase event moves ltv/purchase_count on the next profile read.
- [ ] No PULSE_API_KEY or PII in built frontend assets.
Ask me for: PULSE_API_KEY, the player id mapping, our signup/consent/RG
hooks, and our account-deletion flow.