Skip to main content

[PRD] Supporting Embeddable Create Ticket Form (Web)

HEADER BLOCK

FieldValue
PMZhelia Alifa
PRD Version2.0
StatusDRAFT
PRD TypeSUPPORT
EpicTBD — add once Epic is created
SquadCDP Squad
RFC LinkDRAFT RFC — Embed Ticket in Omnichannel, Phase 1 Backend · DRAFT RFC FE — Embed Ticket in Omnichannel, Phase 1 Frontend (both CRM-owned)
Figma MasterTBD — CDP entry point + embed panel
AnchorYes — Create Ticket & Auto-Associate from CDP (Cross-Platform) — ANCHOR (web track). Lead-squad anchor: Embed Ticket in Omnichannel.
Labelsepic:qontak-cdp | module:customers | feature:embed-create-ticket
Last Updated2026-06-25

This is a SUPPORT PRD. The embeddable Create-Ticket component is owned and built by the CRM squad.


2. SUPPORT Context

FieldDetail
Anchor PRDEmbed Ticket in Omnichannel — ANCHOR. Its "Flexible Embeddable Component (Able to be reused for CDP)" story is the hook for this PRD — but it is a "nice to have", not Phase 1 committed scope.
Lead-squad Phase PRD / RFCsCRM/Omnichannel Phase 1 — BE RFC + FE RFC. Both RFCs explicitly mark "CDP embed reuse" OUT of Phase 1 scope (architecture-friendly, not implemented).
This squad's contribution (CDP)Frontend only: embed the CRM-owned ticket component inside CDP → Customer Detail → Tickets section; send the customer context via EMBED_INIT; handle the TICKET_CREATED / EMBED_CLOSE / TICKET_CREATE_ERROR messages; refresh the associated-tickets list; permission-gate the entry point. CDP does not build the ticket form, the pipeline/layout logic, or the create API — those are CRM's.
Integration point (contract)The CRM Nuxt-layer embed at /embed/ticket/create loaded in an iframe, communicating via the FE RFC's versioned postMessage contract (EMBED_INITTICKET_CREATED/EMBED_CLOSE/TICKET_CREATE_ERROR/EMBED_RESIZE), origin-validated. See §8.
Handoff contract + dateCRM delivers: a CDP-reusable embed (config-driven, accepts an EMBED_INIT from a non-chat host) + a CDP embed_source value in the BE allow-list. CDP delivers: the customer-detail integration. Date: TBD — gated on CRM committing CDP reuse into a phase (currently out of Phase 1 — OQ-1, blocking).
Graceful degradationIf the CRM embed is unavailable / not yet reusable for CDP, the CDP Tickets section degrades to the existing "Associate existing ticket" flow only (POST /v1/leads/{contact_id}/tickets/{ticket_id}) — no create. The feature is additive and never blocks the existing associate/view behavior.

3. One-liner + Problem

One-liner: Let a CDP user create a ticket from the Customer Detail page via the CRM's embeddable ticket form, auto-associated to the customer — at parity with the Embeddable Create Deal Form.

Problem: Today CDP only lets a user associate an existing ticket to a customer (AssociatedTickets.vuePOST /v1/leads/{contact_id}/tickets/{ticket_id}). To raise a new ticket, the user must leave the customer context for the Ticket Dashboard / Omnichannel. The equivalent Deal flow is already embeddable in CDP, so the experience is asymmetric — and support agents working a customer in CDP lose time and context switching out to create a ticket.


4. Target Users + Persona Context

PersonaRoleGoalPainWorkaround
Primary — Support / CS AgentAgent working a customer in CDPRaise a ticket on the customer without leaving the customer recordCDP can't create tickets — only associate existing onesOpens the Ticket Dashboard / Omnichannel in another tab, creates the ticket, then comes back to associate it
Secondary — Sales / CRM AdminAgent/admin managing a customer's recordsKeep ticket + deal creation in one place (Deal already embeds; Ticket doesn't)Inconsistent: Deal embeds in CDP, Ticket doesn'tTreats tickets as a separate, out-of-context task

5. Non-Goals

  1. Not building the ticket form — the create form, pipeline selection, and custom-layout rendering are owned by the CRM embed (FE RFC). CDP only embeds it.
  2. Not building the create API — ticket creation is the CRM's POST /api/mobile/v2.8/tickets (BE RFC). CDP does not add a create endpoint.
  3. No mobile — web only (qontak-customer-fe); the CRM embed Phase 1 is web-only. (Mobile is the sibling SUPPORT PRD.)
  4. No ticket viewing/editing in CDP — Phase 2/3 of the anchor (Unified Viewing & Editing) is out of scope here.
  5. No ticket history surface in CDP — that is the separate anchor scope.
  6. No change to the existing "Associate existing ticket" flow — it stays exactly as today.
  7. No chat-room linking from CDP — CDP has no chat room context; room_id linking (Deal Scenario 1) does not apply (see §8 / OQ-5).

Scope Changes

Engineering surfaces this PRD touches (controlled vocab: Backend · Frontend · Mobile · Infra · Data · Design · Docs · None). CDP-side only; CRM-owned work is a dependency, not CDP scope.

  • Frontendqontak-customer-fe: add a Create-Ticket entry point + embed (iframe to the CRM /embed/ticket/create layer) in AssociatedTickets.vue; send EMBED_INIT with the customer context (qontakCustomerId, contact name/phone/email); handle EMBED_READY / TICKET_CREATED / TICKET_CREATE_ERROR / EMBED_CLOSE / EMBED_RESIZE (origin-validated); on success refresh the associated-tickets list + toast; permission-gate the entry point.
  • Design — Figma for the CDP Create-Ticket entry point + the embed panel placement and its loading / error / success states.
  • Backend (conditional — contact-service) — only if CRM does not auto-associate the CDP-created ticket: CDP calls its existing POST /v1/leads/{contact_id}/tickets/{ticket_id} to associate after TICKET_CREATED (see OQ-6). Otherwise None.
  • Dependency (not CDP scope) — CRM Backend + Frontend — add a CDP embed_source value (e.g. embed-web-cdp) to the BE allow-list; make the embed component reusable for a non-chat (CDP) host; resolve Qontak One auth (see §13, OQ-1/OQ-2).

6. Constraints

ConstraintValue
PlatformWeb only (qontak-customer-fe). The CRM embed Phase 1 is web-only.
Feature flagCRM gates the embed behind unify_ticket_omnichannel_view (per-team, default OFF) (BE RFC). CDP's entry point should additionally be flag-gated for staged rollout — flag name TBD with CRM (OQ-7).
Embed deliveryiframe loading the CRM Nuxt-layer route /embed/ticket/create (FE RFC), served from a CRM subdomain (e.g. crm.qontak.com). Sandboxed; EMBED_RESIZE-driven height.
Auth (grounded — open)The CRM embed authenticates JWT Bearer (v2.8 session) called directly by the webview — not a token query param, not via IAG (BE RFC). Qontak One may authenticate via Mekari unified SSO, not v2.8 JWT — if so the v2.8 endpoints would 401. This is an unresolved, blocking dependency (BE RFC §6; FE RFC Concern #1 / OQ-1).
postMessage contract (grounded)Versioned (version: 1), typed JSON messages with origin validation against an env allowlist (never '*') (FE RFC). Not a {msg: "..."} string. See §8 for the exact event/payload contract.
data_source labeling (grounded)Set server-side by CRM when embed: true, derived from embed_source against the allow-list embed-web-chat / embed-flutter-crm / embed-flutter-chat (client value ignored/overwritten). A CDP value (e.g. embed-web-cdp) must be added to the BE allow-list or the server coerces it to embed-web-chat. The label field is data_source, not source. (BE RFC.)
Contact context transportThe customer context is passed via the EMBED_INIT postMessage payload (qontakCustomerId for Qontak One; contactAccountUniqId otherwise) — not a customer_id/token URL param (FE RFC).
Plan scopeAll Qontak One clients that have CDP + CRM Tickets.
Backward compatThe existing "Associate existing ticket" flow (POST /v1/leads/{contact_id}/tickets/{ticket_id}) is unchanged.

7. New Features

7.1 Create-Ticket entry point + embed in Customer Detail (AssociatedTickets.vue)

ElementBeforeAfter
Tickets section (AssociatedTickets.vue, Customer Detail menu id 4)Only "Associate existing ticket" (POST /v1/leads/{contact_id}/tickets/{ticket_id}); no createAdd a "Create Ticket" entry that opens the CRM embed (iframe → /embed/ticket/create) in a panel, mirroring how AssociatedDeals.vue embeds the Deal form
Customer contextNot passed anywhereOn embed load, CDP sends EMBED_INIT with the customer context (qontakCustomerId, name/phone/email) so the CRM form auto-fills the Contact
On successn/aOn TICKET_CREATED, CDP closes the embed, refreshes the associated-tickets list, and shows a success toast (server-side association — OQ-6)

Component tree (CDP side):

  • AssociatedTickets.vue (existing — extend)
    • CreateTicketEntry — "Create Ticket" button/menu item (permission-gated)
    • TicketEmbedPanel (new) — sandboxed <iframe src="${CRM_EMBED_URL}/embed/ticket/create">
      • postMessage listener — origin-validated EMBED_READY / TICKET_CREATED / TICKET_CREATE_ERROR / EMBED_CLOSE / EMBED_RESIZE
      • EMBED_INIT sender — posts the customer context on EMBED_READY
    • existing AssociatedExistingTickets / TicketsCard / FilterTickets (unchanged)

4 UI States (embed panel):

  • Loading: spinner/skeleton while the iframe loads + until EMBED_READY.
  • Empty: N/A (the panel always renders the CRM form once ready).
  • Error: iframe fails to load or TICKET_CREATE_ERROR → inline error + retry / close; the agent can still use "Associate existing".
  • Success: TICKET_CREATED → panel closes, tickets list refreshes, success toast.

8. API & Webhook Behavior

CDP owns no create API. The "API behavior" here is the embed postMessage contract (CRM-owned, FE RFC) plus the optional CDP association call. CDP must implement to this exact contract.

#BehaviorEntity AffectedTriggered ByExpected BehaviorFailure Behavior
1Initialise the embed with customer contextCRM embed formCDP receives EMBED_READY from the iframeCDP posts EMBED_INIT { version:1, roomId: null, contactName, contactPhone, contactEmail, contactAccountUniqId, qontakCustomerId, channelType, locale } to the iframe origin; the CRM form auto-fills the Contact via qontakCustomerId (Qontak One)Origin mismatch → message dropped; if EMBED_READY never arrives within a timeout → show the embed error state
2Create the ticketCRM Ticket (CRM side)Agent submits the form inside the embedCRM calls POST /api/mobile/v2.8/tickets with embed: true, embed_source (a CDP value — OQ-3), JWT Bearer auth; sets data_source server-side; auto-associates the contact (OQ-6)TICKET_CREATE_ERROR { errorCode, errorMessage } → CDP shows the error; ticket stays creatable via "Associate existing"
3Notify CDP of successCRM emits TICKET_CREATEDPayload { ticketId, ticketName, ticketSlug, pipelineId, pipelineName, stageId, stageName, priorityId, createdAt, dueDate, channelIntegrationRoomId }; CDP validates origin + version, then closes the embed, refreshes the tickets list, shows a success toastIf the payload is malformed / origin invalid → ignored; agent can re-open
4Associate the created ticket to the customerCDP ticket associationAfter TICKET_CREATEDPreferred: CRM auto-associates server-side via the customer context (anchor US#6). Fallback (OQ-6): CDP calls POST /v1/leads/{contact_id}/tickets/{ticket_id} with ticketId from the payloadAssociation fails → log cdp_ticket_embed_associate_failed; ticket still exists in CRM; surface a retry
5Close / cancel the embedAgent cancels, or after successCRM emits EMBED_CLOSE { reason: 'user_cancel' | 'ticket_created' | 'error' } (or CDP sends EMBED_CLOSE_REQUEST); CDP tears down the panel
6Resize the embedForm height changesCRM emits EMBED_RESIZE { height }; CDP sets the iframe height

System Flow — CDP Create-Ticket Embed

sequenceDiagram
participant Agent
participant CDP as customer-fe (AssociatedTickets)
participant Embed as CRM embed (/embed/ticket/create)
participant CRM as CRM API (v2.8/tickets)
Agent->>CDP: Click "Create Ticket"
CDP->>Embed: load iframe
Embed-->>CDP: EMBED_READY (v1)
CDP->>Embed: EMBED_INIT { qontakCustomerId, contact..., roomId:null }
Note over Embed: single pipeline -> bypass; multiple -> pipeline list; render layout
Agent->>Embed: fill form + Submit
Embed->>CRM: POST /api/mobile/v2.8/tickets { embed:true, embed_source }
alt success
CRM-->>Embed: 201 ticket
Embed-->>CDP: TICKET_CREATED { ticketId, ... }
CDP->>CDP: validate origin+version -> close panel, refresh list, toast
opt CRM did not auto-associate (OQ-6)
CDP->>CRM: POST /v1/leads/{contact_id}/tickets/{ticketId}
end
Embed-->>CDP: EMBED_CLOSE { reason: ticket_created }
else failure
CRM-->>Embed: 4xx/5xx
Embed-->>CDP: TICKET_CREATE_ERROR { errorCode, errorMessage }
CDP->>CDP: show error; associate-existing still available
end

9. System Flow + User Stories + ACs

9.1 System Flow

  1. Agent opens a customer in CDP → Customer Detail → Tickets section; if they have ticket-create permission, a "Create Ticket" entry shows.
  2. Clicking it opens the CRM embed (/embed/ticket/create) in a sandboxed iframe panel.
  3. The embed posts EMBED_READY; CDP replies with EMBED_INIT carrying the customer context (qontakCustomerId, contact details).
  4. The CRM form auto-fills the Contact; if the account has one pipeline it renders the form directly, if multiple it shows pipeline selection first, then the layout's fields.
  5. Agent fills + submits; CRM creates the ticket (POST /api/mobile/v2.8/tickets, embed:true, CDP embed_source), sets data_source server-side, and auto-associates the contact.
  6. CRM emits TICKET_CREATED; CDP validates origin + version, closes the panel, refreshes the associated-tickets list, shows a success toast (+ optional CDP association call — OQ-6).
  7. Failure branches: iframe load fails → error state, associate-existing still available; TICKET_CREATE_ERROR → inline error; origin/version invalid → message ignored; agent cancels → EMBED_CLOSE.

9.2 User Stories

User StoryImportanceMockupTechnical NotesAcceptance Criteria
[TCKT-S01] — Open the Create-Ticket embed from CDP

As a Support/CS Agent, I want to open a Create-Ticket form from the Customer Detail page, so that I can raise a ticket without leaving the customer record.
Must HaveFigma: TBD — CDP entry point + embed panelBefore-After: Before — AssociatedTickets.vue only offers "Associate existing". After — a "Create Ticket" entry opens the CRM embed (iframe → /embed/ticket/create) in a panel, mirroring AssociatedDeals.vue.— Happy Path —
• AC-1: Given the user has ticket-create permission and the flag is ON, when they open the Tickets section, then a "Create Ticket" entry is shown.
• AC-2: Given they click "Create Ticket", when the panel opens, then a sandboxed iframe loads /embed/ticket/create and a loading state shows until EMBED_READY.
— Error / Unhappy Path —
• ERR-1: Given the iframe fails to load, then an inline error + retry shows and "Associate existing" remains available.
— Permission Model —
• CAN: users with the ticket-create permission (key — OQ-4).
• CANNOT: users without it — the entry is not rendered.
— UI States —
• Loading: spinner until EMBED_READY. • Empty: N/A. • Error: iframe-load failure message. • Success: form rendered.
[TCKT-S02] — Auto-fill the customer in the embed

As a Support/CS Agent, I want the ticket's Contact pre-filled with the customer I'm viewing, so that I don't re-enter it.
Must HaveFigma: TBD — embed Contact field (read from CRM form)Before-After: Before — no context passed. After — on EMBED_READY, CDP posts EMBED_INIT { qontakCustomerId, contactName, contactPhone, contactEmail, contactAccountUniqId, roomId:null, channelType, locale, version:1 }; the CRM form auto-fills the Contact via qontakCustomerId. Contact context is sent via postMessage, not a URL param (per FE RFC).— Happy Path —
• AC-1: Given the embed posts EMBED_READY, when CDP responds, then it sends EMBED_INIT to the iframe's exact origin with qontakCustomerId = the open customer.
• AC-2: Given a Qontak One customer, when the form initialises, then the Contact field is pre-filled from qontakCustomerId (editable by the agent).
— Error / Unhappy Path —
• ERR-1: Given EMBED_INIT targets a non-allowlisted origin, then CDP does not post it (origin guard).
• ERR-2: Given the customer cannot be resolved by the CRM, then the Contact field is left empty/editable (CRM behavior); CDP still allows submit.
— Permission Model —
• CAN: same as TCKT-S01.
[TCKT-S03] — Confirm creation + refresh on TICKET_CREATED

As a Support/CS Agent, I want CDP to confirm the ticket was created and show it on the customer, so that I see the result in context.
Must HaveFigma: TBD — success toast + refreshed Tickets listBefore-After: Before — n/a. After — CDP listens for the typed TICKET_CREATED message { ticketId, ticketName, pipelineId, stageId, priorityId, createdAt, dueDate, … }, validates event.origin + version:1, then closes the panel, refreshes the associated-tickets list, and toasts. (Corrected vs the earlier {msg} assumption — the FE RFC defines a typed payload.)— Happy Path —
• AC-1: Given the CRM emits TICKET_CREATED from the allowlisted origin with version:1, when CDP receives it, then it closes the embed, refreshes the tickets list (TicketStore.fetchTicketsAssociated), and shows a success toast.
• AC-2: Given EMBED_CLOSE { reason }, when received, then CDP tears down the panel.
• AC-3: Given EMBED_RESIZE { height }, when received, then CDP sets the iframe height.
— Error / Unhappy Path —
• ERR-1: Given a TICKET_CREATED from a non-allowlisted origin or wrong version, then CDP ignores it.
• ERR-2: Given TICKET_CREATE_ERROR { errorCode, errorMessage }, then CDP surfaces the error inline; the panel stays open for retry.
— UI States —
• Loading: N/A. • Empty: N/A. • Error: TICKET_CREATE_ERROR message. • Success: toast + refreshed list.
[TCKT-S04] — Created ticket is associated to the customer

As a Support/CS Agent, I want the created ticket linked to this customer automatically, so that it shows under their Tickets.
Must HaveFigma: N/A — data linkageBefore-After: Before — n/a. After — preferred: CRM auto-associates server-side via the customer context (anchor US#6). Fallback (OQ-6): CDP calls POST /v1/leads/{contact_id}/tickets/{ticketId} using ticketId from TICKET_CREATED.— Happy Path —
• AC-1: Given CRM auto-associates the contact server-side, when TICKET_CREATED arrives, then the refreshed list already shows the new ticket — CDP makes no association call.
• AC-2: Given CRM does not auto-associate for the CDP path (OQ-6), when TICKET_CREATED arrives, then CDP calls POST /v1/leads/{contact_id}/tickets/{ticketId} and then refreshes.
— Error / Unhappy Path —
• ERR-1: Given the fallback association call fails, then cdp_ticket_embed_associate_failed is logged and a retry is offered; the ticket still exists in CRM.
[TCKT-S05] — data_source labels the ticket as CDP-originated

As a Data Analyst, I want CDP-created tickets tagged with a CDP origin, so that we can distinguish them.
Should HaveFigma: N/A — backend labelBefore-After: Before — only embed-web-chat / embed-flutter-crm / embed-flutter-chat exist in the BE allow-list. After — a CDP embed_source (e.g. embed-web-cdp) is added to the BE allow-list and sent on create; CRM sets data_source server-side. (Corrected vs the earlier source: cdp-embed assumption — field is data_source, value must be allow-listed.)— Happy Path —
• AC-1: Given the embed is opened from CDP, when the ticket is created, then embed: true + the CDP embed_source are sent and the stored data_source reflects the CDP origin.
— Error / Unhappy Path —
• ERR-1: Given the CDP embed_source is not in the BE allow-list, then the server coerces data_source to embed-web-chat (the bug this story prevents) — blocked until the allow-list is updated (dependency / OQ-3).
[TCKT-S06] — Pipeline + custom layout inherited from CRM

As a Support/CS Agent, I want pipeline selection + the right custom layout in the embed, so that I capture the required fields.
Should HaveFigma: see FE RFC (TicketEmbedPipelineSelect, TicketsLayoutSelector)Before-After: Before — n/a. After — inherited from the CRM embed (FE RFC reuses useTicketPipeline / useTicketLayout): single pipeline → bypass; multiple → selection list; then dynamic fields per layout. No CDP logic.— Happy Path —
• AC-1: Given one ticket pipeline, when the embed opens, then it bypasses selection and renders the default pipeline's layout.
• AC-2: Given multiple pipelines, when the embed opens, then a pipeline list shows, then the chosen pipeline's layout renders. (CRM-owned; CDP only hosts the iframe.)
[TCKT-S07-NEG] — No create without permission / flag (Guard Rail — from Non-Goals)

As the system, when a user without ticket-create permission or with the flag OFF tries to create, the action is blocked.
Guard Rail• NEG-1: Given the user lacks ticket-create permission, then the "Create Ticket" entry is not rendered.
• NEG-2: Given the embed flag is OFF for the company, then the entry is hidden and the Tickets section behaves exactly as today (associate-existing only).

Dependencies: TCKT-S02–S06 depend on the CRM embed being reusable for CDP (a non-chat host) — currently OUT of Phase 1 in both RFCs (OQ-1, blocking). TCKT-S02 depends on the EMBED_INIT contract; TCKT-S05 depends on the BE allow-list change (OQ-3).

Test Coverage Matrix — [TCKT-S01]

DimensionCoverageNotes
Boundary values⚠️ partialAC covers permission + flag; ⚠️ QA: slow iframe load, EMBED_READY timeout
State transitions✅ definedopen → loading → ready; load-fail → error
Data validation✅ definedorigin guard on all messages
Concurrency⚠️ TBD⚠️ QA: open the embed while an associate-existing modal is open
Network/timeout✅ definedERR-1 iframe load failure

Test Coverage Matrix — [TCKT-S03]

DimensionCoverageNotes
Boundary values⚠️ partial⚠️ QA: TICKET_CREATED with missing optional fields (dueDate null)
State transitions✅ definedcreated → close → refresh; error → stay open
Data validation✅ definedorigin + version validation (ERR-1)
Concurrency⚠️ TBD⚠️ QA: duplicate TICKET_CREATED messages
Network/timeout✅ definedERR-2 TICKET_CREATE_ERROR

10. Rollout

FieldDetail
FlagCRM unify_ticket_omnichannel_view (per-team, default OFF) + a CDP entry-point flag (name TBD — OQ-7).
Stage 1 — Internal QAEnable on a QA company once CRM ships a CDP-reusable embed; verify EMBED_INIT auto-fill, TICKET_CREATED refresh, data_source, association.
Stage 2 — Closed Beta3–5 Qontak One companies; monitor create success + association rate.
Stage 3 — GAProgressive per-company enable.
Backward compatAssociate-existing flow unchanged; create is additive and flag-gated.
Dependency gateCannot start before CRM commits CDP reuse into a phase (OQ-1) and adds the CDP embed_source (OQ-3) + resolves Qontak One auth (OQ-2).

11. Observability

Event NameTriggerProperties
cdp_ticket_embed_openedThe Create-Ticket embed is opened from CDPcompany_sso_id, contact_id, qontak_customer_id, user_id
cdp_ticket_embed_createdTICKET_CREATED received + validatedcontact_id, ticket_id, pipeline_id, data_source
cdp_ticket_embed_create_errorTICKET_CREATE_ERROR receivedcontact_id, error_code
cdp_ticket_embed_associate_failedFallback association call failed (OQ-6)contact_id, ticket_id, reason
cdp_ticket_embed_init_droppedEMBED_INIT blocked by origin guardcompany_sso_id, attempted_origin

Dashboard owner: CDP Squad. Alerts: cdp_ticket_embed_create_error rate > 10% → Slack #cdp-ops; associate-failed > 5% → investigate. Cadence: weekly for the first 4 weeks post-GA.


12. Success Metrics

MetricDefinitionBaselineTarget
⭐ Adoption — CDP ticket creation% of tickets on Qontak One customers created via the CDP embed (where flag ON) within 30 days of GA0 (capability is net-new)≥ X% (set with CRM at beta)
⭐ Create reliabilitycreated / (created + create_error)N/A≥ 99%
Association successassociated / createdN/A≥ 99%
ParityTicket create available wherever Deal create isDeal-only today100% of CDP customer-detail surfaces

13. Dependencies

DependencyOwning TeamDeliverable NeededBlocking?
CDP-reusable embed componentCRM/OmnichannelMake the /embed/ticket/create layer usable by a non-chat (CDP) host (accept an EMBED_INIT without a chat room). Currently OUT of Phase 1 in both RFCs.YES
Qontak One auth resolutionCRM + PlatformConfirm the embed authenticates correctly for Qontak One (v2.8 JWT vs Mekari SSO) — else the create call 401s. (BE RFC §6, FE RFC Concern #1)YES
CDP embed_source in BE allow-listCRM BackendAdd a CDP value (e.g. embed-web-cdp) to ALLOWED_EMBED_SOURCES so CDP-origin tickets are labeled correctlyYES (for TCKT-S05)
postMessage contractCRM FrontendThe versioned EMBED_INIT/TICKET_CREATED/… contract (FE RFC)YES
Ticket-create permission keyCRM + CDPThe permission key gating the CDP "Create Ticket" entry (CanCan-inherited; key TBD — OQ-4)YES
qontak-customer-fe integrationCDP SquadEmbed + EMBED_INIT sender + message handlers + list refresh + permission gate in AssociatedTickets.vueYES (CDP scope)

Dependency Graph — CDP Create-Ticket Embed

graph LR
F[CDP Create-Ticket embed] -->|BLOCKING - OUT of Phase 1| REUSE[CRM: CDP-reusable embed]
F -->|BLOCKING| AUTH[Qontak One auth v2.8 vs SSO]
F -->|BLOCKING| SRC[CRM: embed-web-cdp in allow-list]
F -->|BLOCKING| PM[postMessage contract EMBED_INIT/TICKET_CREATED]
F -->|YES| PERM[ticket-create permission key]
F -->|CDP scope| FE[customer-fe: AssociatedTickets embed]

14. Key Decisions + Alternatives Rejected

14a — Decisions Made

IDDecisionRationale (grounded)
D-1Consume the CRM-owned embed; build nothing CDP-native.Parity with the Deal embed; the form/pipeline/layout/create API are all CRM's (BE+FE RFCs).
D-2Use the FE RFC's typed postMessage contract (EMBED_INITTICKET_CREATED/TICKET_CREATE_ERROR/EMBED_CLOSE/EMBED_RESIZE, version:1, origin-validated).Grounded in the FE RFC. Supersedes the earlier {msg:"Ticket successfully created"} assumption (that mirrored the shipped Deal embed, not the new contract).
D-3Pass the customer context via EMBED_INIT postMessage, keyed on qontakCustomerId — not a customer_id/token URL param.Grounded in the FE RFC (EMBED_INIT payload) + Deal parity (qontak_customer_id).
D-4Label via data_source from an allow-listed embed_source; add a CDP value to the BE allow-list.Grounded in the BE RFC (server-side data_source; client value ignored). Replaces the earlier source=cdp / source: cdp-embed assumption.
D-5Degrade gracefully to associate-existing if the embed is unavailable.The embed is additive; CDP already has the associate path.

14b — Alternatives Rejected

AlternativeWhy Rejected
{msg: "..."} string postMessage (mirror the shipped Deal embed)The new FE RFC defines a typed, versioned payload — the {msg} shape would not interoperate with the Phase 1 component.
token + customer_id in the iframe URLThe BE RFC uses direct JWT Bearer (no token query param); the FE RFC passes contact via EMBED_INIT, not the URL.
source: cdp-embed labelField is data_source; value must be in the BE allow-list — an arbitrary client value is overwritten server-side.
Build a native CDP ticket formDuplicates CRM logic and perpetuates the parity-lag the anchor exists to remove.

15. Open Questions

#TypeQuestionMitigation / DefaultOwnerDeadline
OQ-1Risk (blocking)CDP embed reuse is OUT of Phase 1 in both RFCs. When will CRM commit a CDP-reusable embed (non-chat host) to a phase? Without it, this PRD cannot be built.Escalate to CRM/Omnichannel to schedule CDP reuse; until then CDP stays associate-existing only.PM + CRM2026-07-04
OQ-2Risk (blocking)Qontak One auth: does the embed work with Qontak One's auth (v2.8 JWT vs Mekari SSO), or will the create call 401?Confirm with CRM + Platform before beta; block GA until resolved.CRM + Platform2026-07-04
OQ-3DecisionWhat CDP embed_source value (e.g. embed-web-cdp) and who adds it to the BE ALLOWED_EMBED_SOURCES allow-list?Propose embed-web-cdp; CRM Backend adds it.CDP + CRM BE2026-07-04
OQ-4Open QuestionWhich permission key gates the CDP "Create Ticket" entry? (CanCan-inherited per anchor US#5, but the CDP key is unnamed.)Confirm with CRM; reuse the ticket-create permission.PM + CDP2026-07-04
OQ-5Open QuestionDoes a CDP-created ticket need any chat/room linkage (Deal Scenario 1 auto-links a chat)? CDP has no room.Default: no room linkage for CDP (roomId: null in EMBED_INIT).PM2026-07-04
OQ-6DecisionDoes CRM auto-associate the contact for the CDP path, or must CDP call POST /v1/leads/{contact_id}/tickets/{ticketId} after TICKET_CREATED?Confirm with CRM; if not auto-associated, CDP makes the call (adds a Backend touch — see Scope Changes).CDP + CRM2026-07-04
OQ-7Open QuestionCDP entry-point feature-flag name + relation to CRM's unify_ticket_omnichannel_view.Add a CDP-side flag for staged rollout; align with CRM.CDP2026-07-04
OQ-8Open QuestionEmbed surface: inline panel inside the Tickets section vs a side sheet/modal (Deal uses a panel)?Default: inline panel like the Deal embed; confirm with Figma.Design2026-07-04

PRD CHANGELOG

VersionDateBySectionTypeSummary
2.02026-06-25Reformat + RFC groundingAllREWRITEReformatted from the Product-Planning template into the AI-SDLC template (HEADER BLOCK, ToC, §1–15, ## Scope Changes section, split Mockup / Technical Notes story columns). Grounded against the CRM BE RFC + FE RFC and corrected the embed contract: typed EMBED_INIT/TICKET_CREATED postMessage (not {msg}); data_source via allow-listed embed_source (not source=cdp); contact via qontakCustomerId in EMBED_INIT (not a customer_id/token URL param); JWT/SSO auth open. Surfaced the headline risk: CDP reuse is OUT of Phase 1 in both RFCs (OQ-1, blocking). Stories rewritten as TCKT-S01–S07-NEG with Gherkin ACs + 2 test matrices.
1.02026-06-22Initial draftAllCREATEDFirst draft (Product-Planning format) mirroring the Embeddable Create Deal Form.