---
id: AUTH-MKT
title: Marketing Authorization Model
product_area: marketing
revision: 1
status: draft
design_intent: proposed
implementation_evidence: partially-observed
source_sha:
  services-marketing: d071a159fe9782bb71ff246d5c67d5bbfe07fbfa
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
  rhythm-v2-docs: 61e160782cedd17e715344bb961aec2e8d209de3
scopes:
  - name: workspace
    meaning: Marketing resource operations require authority for the selected workspace.
    provenance: observed
    source: 'services-marketing:modules/marketing/aws/api/marketing.routes.ts:marketingRoutes'
  - name: source record
    meaning: >-
      Evaluation retains the evaluating person’s query visibility; this is a source-service guard rather than
      a Marketing record grant.
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-015-decide-every-request-against-the-caller-s-grants.md
roles:
  - id: ROLE-MKT-001
    name: Marketing Read Only
    who: A person whose customer role includes the Marketing read-tier policy.
    grants:
      - marketing.application.access
      - marketing.audiences.view
    provenance: inferred
    source:
      - 'services-marketing:aws/marketing.service.ts:MARKETING_PUBLISHED_PERMISSIONS'
      - >-
        rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-013-ship-rhythm-s-built-in-roles-and-policies-with-each-release.md
    note: >-
      These are entitlement profiles derived from declared tiers and Platform tier generation, not evidence of
      installed Marketing-specific roles or a customer assignment.
  - id: ROLE-MKT-002
    name: Marketing User
    who: A person whose customer role includes the Marketing user-tier policy.
    grants:
      - marketing.application.access
      - marketing.audiences.view
      - marketing.audiences.manage
      - marketing.lists.manage
    provenance: inferred
    source:
      - 'services-marketing:aws/marketing.service.ts:MARKETING_PUBLISHED_PERMISSIONS'
      - >-
        rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-013-ship-rhythm-s-built-in-roles-and-policies-with-each-release.md
    note: >-
      These are entitlement profiles derived from declared tiers and Platform tier generation, not evidence of
      installed Marketing-specific roles or a customer assignment.
  - id: ROLE-MKT-003
    name: Marketing Administrator
    who: A person whose customer role includes the Marketing administrator-tier policy.
    grants:
      - marketing.application.access
      - marketing.audiences.view
      - marketing.audiences.manage
      - marketing.audiences.include-excluded-statuses
      - marketing.lists.manage
    provenance: inferred
    source:
      - 'services-marketing:aws/marketing.service.ts:MARKETING_PUBLISHED_PERMISSIONS'
      - >-
        rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-013-ship-rhythm-s-built-in-roles-and-policies-with-each-release.md
    note: >-
      These are entitlement profiles derived from declared tiers and Platform tier generation, not evidence of
      installed Marketing-specific roles or a customer assignment.
permissions:
  - key: marketing.application.access
    intent: 'Open Marketing within an authorized, licensed workspace.'
    operations: []
    surfaces:
      - console
    guarded_by:
      - BR-CAP-MKT-MKT-017-05
      - BR-CAP-MKT-MKT-017-08
    tier: read
    provenance: observed
    source: 'services-marketing:aws/marketing.service.ts:MARKETING_PUBLISHED_PERMISSIONS'
  - key: marketing.audiences.view
    intent: Read audience definitions and evaluations and request previews or complete counts.
    operations:
      - listAudiences
      - getAudience
      - previewAudience
      - countAudience
      - getAudienceEvaluation
      - countEveryone
    surfaces:
      - console
      - api
      - job
    guarded_by:
      - BR-CAP-MKT-MKT-009-10
      - BR-CAP-MKT-MKT-010-01
      - BR-CAP-MKT-MKT-010-04
      - BR-CAP-MKT-MKT-010-05
      - BR-CAP-MKT-MKT-010-07
      - BR-CAP-MKT-MKT-017-05
      - BR-CAP-MKT-MKT-017-06
    tier: read
    provenance: observed
    source: 'services-marketing:modules/marketing/aws/api/marketing.routes.ts:marketingRoutes'
  - key: marketing.audiences.manage
    intent: Maintain and retire audience definitions and take responsibility for their ownership.
    operations:
      - createAudience
      - updateAudience
      - archiveAudience
      - takeAudienceOwnership
      - repinAudience
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-MKT-MKT-001-03
      - BR-CAP-MKT-MKT-001-11
      - BR-CAP-MKT-MKT-005-01
      - BR-CAP-MKT-MKT-005-02
      - BR-CAP-MKT-MKT-011-02
      - BR-CAP-MKT-MKT-011-06
      - BR-CAP-MKT-MKT-012-04
      - BR-CAP-MKT-MKT-017-05
      - BR-CAP-MKT-MKT-017-06
    tier: user
    provenance: observed
    source: 'services-marketing:modules/marketing/aws/api/marketing.routes.ts:marketingRoutes'
  - key: marketing.audiences.include-excluded-statuses
    intent: Authorize a newly enabled inactive or deceased contact inclusion alongside audience management.
    operations:
      - createAudience
      - updateAudience
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-MKT-MKT-005-01
      - BR-CAP-MKT-MKT-005-02
      - BR-CAP-MKT-MKT-005-07
      - BR-CAP-MKT-MKT-005-10
    tier: admin
    sensitive: true
    provenance: observed
    source: 'services-marketing:aws/marketing.service.ts:MARKETING_PUBLISHED_PERMISSIONS'
  - key: marketing.lists.manage
    intent: Read and maintain manual lists and their contact memberships.
    operations:
      - listLists
      - createList
      - getList
      - updateList
      - archiveList
      - listListMembers
      - addListMember
      - removeListMember
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-MKT-MKT-014-04
      - BR-CAP-MKT-MKT-014-05
      - BR-CAP-MKT-MKT-015-03
      - BR-CAP-MKT-MKT-015-06
      - BR-CAP-MKT-MKT-017-05
      - BR-CAP-MKT-MKT-017-06
    tier: user
    provenance: observed
    source: 'services-marketing:modules/marketing/aws/api/marketing.routes.ts:marketingRoutes'
  - key: crm.contacts.query
    intent: Read recipient contact facts through the source-query service under the evaluator’s authority.
    operations:
      - previewAudience
      - countAudience
      - countEveryone
    surfaces:
      - api
      - job
      - console
    guarded_by:
      - BR-CAP-MKT-MKT-010-01
      - BR-CAP-MKT-MKT-010-05
      - BR-CAP-MKT-MKT-010-08
    owner: CRM
    provenance: documented
    source: >-
      services-marketing:docs/milestones/MKT-M2.md#6. A user without crm.contacts.query cannot preview an
      audience
    note: External prerequisite; no Marketing tier profile grants this key.
  - key: 'none: cloud credentials allowed to invoke the function; no console or customer route'
    intent: Invoke the operations probe through authorized Rhythm cloud credentials.
    operations:
      - laneCheck
    surfaces:
      - job
    guarded_by:
      - BR-CAP-MKT-MKT-018-06
      - BR-CAP-MKT-MKT-018-09
    kind: operation-access-marker
    provenance: documented
    source:
      - >-
        services-marketing:modules/communications/services/lane-check/run-lane-check.ts:runLaneCheck;
        services-marketing:modules/communications/tests/unit/lane-check.spec.ts
    note: >-
      Exact access declaration retained for service-contract cross-checking; this is not a grantable customer
      permission key.
  - key: 'none: an in-process read under the workspace’s row-level security'
    intent: Read suppression facts within the caller’s workspace context.
    operations:
      - suppressedAddressesAmong
    surfaces:
      - service
    guarded_by:
      - BR-CAP-MKT-MKT-004-03
    kind: operation-access-marker
    provenance: documented
    source:
      - >-
        services-marketing:modules/communications/services/persistence/communication-suppressions.ts:suppressedAddressesAmong;
        services-marketing:modules/marketing/tests/integration/services/audience-evaluation.integration.spec.ts#answers
        an address with an active suppression, whatever its case or spacing
    note: >-
      Exact access declaration retained for service-contract cross-checking; this is not a grantable customer
      permission key.
  - key: 'none: an in-process call'
    intent: Submit internally within the authorized workspace transaction.
    operations:
      - submitInTransaction
    surfaces:
      - service
    guarded_by:
      - BR-CAP-MKT-MKT-018-07
    kind: operation-access-marker
    provenance: documented
    source:
      - >-
        services-marketing:modules/communications/services/persistence/communication-submissions.ts:submitInTransaction
    note: >-
      Exact access declaration retained for service-contract cross-checking; this is not a grantable customer
      permission key.
  - key: 'none: public health route'
    intent: Read public service health without a customer grant.
    operations:
      - marketingHealth
    surfaces:
      - api
    guarded_by: []
    kind: operation-access-marker
    provenance: unknown
    source:
      - FND-MKT-MKT-050
    note: >-
      Exact access declaration retained for service-contract cross-checking; this is not a grantable customer
      permission key.
  - key: 'none: invoked by the count state machine; the job was submitted under marketing.audiences.view'
    intent: Execute an authorized count submission through the designated machine entry point.
    operations:
      - countEveryone
    surfaces:
      - job
    guarded_by:
      - BR-CAP-MKT-MKT-009-11
      - BR-CAP-MKT-MKT-010-03
      - BR-CAP-MKT-MKT-010-07
    kind: operation-access-marker
    provenance: documented
    source:
      - >-
        services-marketing:modules/marketing/services/evaluation/count-everyone-task.ts:countEveryoneOperation;
        services-marketing:modules/marketing/tests/integration/services/count-everyone-job.integration.spec.ts#Count
        everyone as a durable job
    note: >-
      Exact access declaration retained for service-contract cross-checking; this is not a grantable customer
      permission key.
  - key: 'none: scheduled'
    intent: Run internal scheduled reconciliation through its machine entry point.
    operations:
      - reconcileJobs
    surfaces:
      - job
    guarded_by:
      - BR-CAP-MKT-MKT-009-06
    kind: operation-access-marker
    provenance: documented
    source:
      - 'services-marketing:modules/marketing/aws/logic/count-everyone-jobs.lambda.ts:jobReconcilerFunction'
    note: >-
      Exact access declaration retained for service-contract cross-checking; this is not a grantable customer
      permission key.
  - key: database role rhythm_crm_app only
    intent: Restrict merge participation to CRM’s database execution role.
    operations:
      - mergePlanContacts
      - mergeApplyContacts
    surfaces:
      - database
    guarded_by:
      - BR-CAP-MKT-MKT-016-07
      - BR-CAP-MKT-MKT-016-10
    kind: operation-access-marker
    provenance: documented
    source:
      - >-
        services-marketing:tests/integration/db/merge-participant.integration.spec.ts#plans six memberships to
        handle, four moved and two dropped, and no blocker
      - >-
        services-marketing:tests/integration/db/merge-participant.integration.spec.ts#lets CRM’s application
        role execute both functions
    note: >-
      Exact access declaration retained for service-contract cross-checking; this is not a grantable customer
      permission key.
  - key: 'none: an in-process library call'
    intent: Calculate recipients inside an authorized caller using supplied inputs.
    operations:
      - resolveRecipients
      - planRelationship
      - resolveRecordPeople
      - evaluateGate
      - selectAddress
      - dedupeRecipients
      - buildCountChain
    surfaces:
      - service
    guarded_by: []
    kind: operation-access-marker
    provenance: documented
    source:
      - >-
        services-marketing:modules/resolution/services/resolution/resolve-recipients.ts:resolveRecipients;
        services-marketing:modules/resolution/tests/unit/resolve-recipients.spec.ts
      - >-
        services-marketing:modules/resolution/services/resolution/relationships.ts:planRelationship;
        services-marketing:modules/resolution/tests/unit/relationships.spec.ts
      - >-
        services-marketing:modules/resolution/services/resolution/relationships.ts:resolveRecordPeople;
        services-marketing:modules/resolution/tests/unit/relationships.spec.ts
      - >-
        services-marketing:modules/resolution/services/resolution/eligibility-gate.ts:evaluateGate;
        services-marketing:modules/resolution/tests/unit/eligibility-gate.spec.ts
      - >-
        services-marketing:modules/resolution/services/resolution/address-rule.ts:selectAddress;
        services-marketing:modules/resolution/tests/unit/address-rule.spec.ts
      - >-
        services-marketing:modules/resolution/services/resolution/deduplication.ts:dedupeRecipients;
        services-marketing:modules/resolution/tests/unit/deduplication.spec.ts
      - 'services-marketing:modules/resolution/services/resolution/count-chain.ts:buildCountChain'
    note: >-
      Exact access declaration retained for service-contract cross-checking; this is not a grantable customer
      permission key.
staff_access: >-
  Platform owns staff entry through an active approved, standing or emergency customer-access grant and a
  corresponding customer role assignment. HQ authority alone supplies no Marketing resource access. The
  delivery probe instead uses Rhythm cloud invocation authority and exposes no customer route.
provenance: inferred
source:
  - 'services-marketing:aws/marketing.service.ts:MARKETING_PUBLISHED_PERMISSIONS'
  - 'services-marketing:modules/marketing/aws/api/marketing.routes.ts:marketingRoutes'
  - 'services-marketing:modules/marketing/services/audiences/audience-rules.ts:resolveStatusRule'
  - 'services-marketing:modules/marketing/services/persistence/audiences.ts'
  - 'services-marketing:modules/marketing/services/persistence/lists.ts'
  - 'services-marketing:modules/marketing/services/evaluation/audience-evaluations.ts'
  - >-
    services-marketing:modules/marketing/services/evaluation/count-everyone-job.ts:registerCountEveryoneJobType
  - 'services-marketing:modules/marketing/tests/e2e/audiences.e2e.spec.ts'
  - 'services-marketing:modules/marketing/tests/e2e/lists.e2e.spec.ts'
  - 'services-marketing:modules/marketing/tests/e2e/audience-evaluation.e2e.spec.ts'
  - 'services-marketing:docs/migrations/communications-wiring/README.md'
  - 'react-console:components/marketing/audiences/audience-editor.tsx'
  - 'react-console:components/marketing/audiences/audience-preview.tsx'
  - 'react-console:components/marketing/lists/list-detail.tsx'
  - >-
    rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-013-ship-rhythm-s-built-in-roles-and-policies-with-each-release.md
  - >-
    rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-015-decide-every-request-against-the-caller-s-grants.md
  - >-
    rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-017-let-rhythm-staff-into-a-customer-s-workspace-only-by-consent.md
  - 'rhythm-v2-docs:specs/platform/security/design/contracts/SVC-PFM-SEC-security.md'
  - >-
    rhythm-v2-docs:specs/platform/security/design/decisions/ADR-PFM-SEC-010-shared-definitions-are-reconciled-from-each-release-and-change.md
evidence:
  - 'services-marketing:aws/marketing.service.ts:MARKETING_PUBLISHED_PERMISSIONS'
  - 'services-marketing:modules/marketing/aws/api/marketing.routes.ts:marketingRoutes'
  - 'services-marketing:modules/marketing/services/audiences/audience-rules.ts:resolveStatusRule'
  - 'services-marketing:modules/marketing/services/persistence/audiences.ts'
  - 'services-marketing:modules/marketing/services/persistence/lists.ts'
  - 'services-marketing:modules/marketing/services/evaluation/audience-evaluations.ts'
  - >-
    services-marketing:modules/marketing/services/evaluation/count-everyone-job.ts:registerCountEveryoneJobType
  - 'services-marketing:modules/marketing/tests/e2e/audiences.e2e.spec.ts'
  - 'services-marketing:modules/marketing/tests/e2e/lists.e2e.spec.ts'
  - 'services-marketing:modules/marketing/tests/e2e/audience-evaluation.e2e.spec.ts'
  - 'services-marketing:docs/migrations/communications-wiring/README.md'
  - 'react-console:components/marketing/audiences/audience-editor.tsx'
  - 'react-console:components/marketing/audiences/audience-preview.tsx'
  - 'react-console:components/marketing/lists/list-detail.tsx'
  - >-
    rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-013-ship-rhythm-s-built-in-roles-and-policies-with-each-release.md
  - >-
    rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-015-decide-every-request-against-the-caller-s-grants.md
  - >-
    rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-017-let-rhythm-staff-into-a-customer-s-workspace-only-by-consent.md
  - 'rhythm-v2-docs:specs/platform/security/design/contracts/SVC-PFM-SEC-security.md'
  - >-
    rhythm-v2-docs:specs/platform/security/design/decisions/ADR-PFM-SEC-010-shared-definitions-are-reconciled-from-each-release-and-change.md
---

# Marketing Authorization Model

## Authorization Boundary

Audience and list operations belong to an authorized workspace. Application entry and licensing come from Platform; resource operations then check their declared Marketing authority. The public health check is the anonymous exception and exposes no business records. Recipient calculation helpers are internal calls, and contact-merge participation is restricted to CRM’s database role. Scheduled recovery and count execution use machine entry points rather than public customer operations.

Rhythm staff enter a customer workspace through Platform’s customer-access grants and role assignments. Staff headquarters authority alone does not provide Marketing access. The delivery probe is an operations tool reached through cloud invocation authority, with no customer permission or console screen.

## Scopes

Marketing declares its customer operation permissions at workspace level. An audience owner is accountable for a definition, but ownership is not an independent access grant. Source-record visibility remains a separate query-service boundary when a person evaluates an audience. Marketing declares no organizational-unit or per-audience permission grant.

Platform evaluates the caller’s workspace reach and signed authority. Existing gateway decisions can survive an access change for their cache lifetime, while staff-entry records describe a separate signed-authority expiry bound. Marketing relies on those Platform contracts; it makes no immediate-revocation promise of its own.

## Roles

The three Marketing profiles describe the read, user and administrator tier policies inferred from the published permission declarations and Platform’s tier-generation contract. They are entitlement profiles within customer roles, rather than newly installed Marketing-specific roles. Read Only supports reach review; User adds preparation and manual group maintenance; Administrator adds sensitive contact-status inclusion.

Platform owns built-in and customer-defined roles, policy composition, assignments and revocation. Actual access depends on those assignments and their scope. Custom roles can separate audience management from list management; either permission can exist without the other. The profiles below do not establish a particular customer’s grants or prove that a release has reconciled them.

## Permission Catalogue

| Permission | Intent | Tier | Additional Boundary |
|---|---|---|---|
| marketing.application.access | Open the application. | Read | Workspace reach and licensing. |
| marketing.audiences.view | Read definitions and evaluations; request previews and counts. | Read | The evaluator’s source-query authority. |
| marketing.audiences.manage | Maintain, retire and take ownership of audiences. | User | Current version, record state and sensitive-change checks. |
| marketing.audiences.include-excluded-statuses | Permit newly enabled exceptional contact-status inclusion. | Administrator, sensitive | Audience management and explicit confirmation. |
| marketing.lists.manage | Read and maintain lists and memberships. | User | List state, edit version and membership validation. |

Contact query authority is an external prerequisite held independently of the Marketing profiles. The structured catalogue also retains the service contracts’ exact public and internal access declarations as marked boundary entries. These declarations are not grantable customer permissions.

The structured catalogue associates each key with its operations, surfaces and additional rule references. Application access has no dedicated Marketing HTTP operation. Background count execution inherits an authorized submission and retains the requester for source queries. Cloud invocation and CRM database execution are separate machine boundaries, not additional customer permission keys.

## Role Entitlement Matrix

| Permission | Read Only Profile | User Profile | Administrator Profile |
|---|---|---|---|
| marketing.application.access | Yes | Yes | Yes |
| marketing.audiences.view | Yes | Yes | Yes |
| marketing.audiences.manage | — | Yes | Yes |
| marketing.audiences.include-excluded-statuses | — | — | Yes |
| marketing.lists.manage | — | Yes | Yes |
| crm.contacts.query | Separate grant | Separate grant | Separate grant |

This matrix describes the cumulative tier profiles. A custom role’s policy composition can differ, and a sensitive permission alone supplies no general audience editing authority.

## Protected Actions

Sensitive inclusion combines audience management, the sensitive grant and the confirmation guard defined in the audience contracts. Takeover uses ordinary audience management in the present contract; the open product question considers whether unilateral takeover needs narrower authority. Archiving and replacing a saved-query copy use the version and state guards of their owning capabilities. List membership changes use the list’s state and uniqueness guards.

CRM merge participation, scheduled recovery and the delivery probe have distinct machine boundaries. None provides a shortcut for a customer caller to acquire broader source-record access.

## Guards Distinguished From Permissions

A permission establishes whether a person may attempt an operation. A guard evaluates the particular record, requested change or source visibility after that authority is established. Workspace isolation, archive state, version comparison, confirmation and dataset query access serve different purposes and remain separately identified in the structured catalogue.

Hiding an action in the console helps a person understand available work, but the service still enforces the operation boundary. The existing editor finding records controls that remain interactive in read-only states; the authorization model does not treat their presentation as proof of server authority.

## What People See When Refused

The console hides inaccessible Marketing screens and presents a refusal page for list access without authority. A readable audience can appear with editing restricted. Attempts to enable sensitive inclusion without authority or confirmation produce distinct permission and validation refusals. A stale write produces a conflict, while an unavailable workspace record is reported as not found.

A preview refused by source-query authorization explains that the person cannot query the audience’s records. A complete count can be accepted first and later show that same permission failure as its failed outcome. Neither refusal is shown as an empty successful audience. Temporary source-service failures follow retry and unavailable-result handling. The findings record remaining limits in error redaction and failure settlement.
