Skip to content

This guide explains how departmental systems (CRMs, workflow apps) and downstream consumers (analytics, client processing) integrate with Deal Engine deal programs.

Deal programs are independent services (one per deal type family) but expose a standard interface so callers don’t learn custom APIs per domain.

Key concepts

  • Deal type: e.g., touring_calcs_v1, endorsement_v1, film_backend_v1
  • Model version: immutable version of a deal type definition (schema + clause structure + templates + computation catalog)
  • Draft: ephemeral workspace for interactive data entry + what-if (not persisted as a deal)
  • Deal: persisted record with immutable revisions and snapshots
  • Snapshot: immutable computed state used for deltas and CP integration
  • Obligations: the finance-facing line items derived from the deal (what CP consumes)

Service discovery (no facade)

Callers first locate the correct deal program base URL via the Model Registry:

  1. GET {registry}/deal-types/{dealType}
  2. Response includes:
    • serviceBaseUrl
    • active model version (and optional canary rules)

Call the deal program at serviceBaseUrl using the standard endpoints below.

Authentication and authorization

  • AuthN: Entra ID JWTs (validated by gateway / services).
  • Gateway: Azure API Management (APIM) is the default entrypoint.
  • AuthZ: AWS Verified Permissions using Cedar policy language.
    • AuthZ may be enforced at APIM and/or inside services (background jobs are always service-side).
    • Deny responses should include an authzDecisionId for audit correlation.

Clients should:

  • send the user bearer token as usual
  • propagate correlation headers (see Observability)

Observability headers

Clients should set / propagate:

  • x-correlation-id (request correlation)
  • x-request-id (if you already use one)

Services emit traces/metrics/logs to Datadog.

Standard endpoints (high level)

Model discovery

  • GET /models
  • GET /models/{dealType}/versions
  • GET /models/{dealType}/versions/{version}
  • GET /models/{dealType}/versions/{version}/input-schema
  • GET /models/{dealType}/versions/{version}/ui-schema (optional)
  • GET /models/{dealType}/versions/{version}/workflow
  • GET /models/{dealType}/versions/{version}/calculations

Drafts (interactive entry + what-if)

  • POST /drafts
  • PATCH /drafts/{draftId}
  • POST /drafts/{draftId}/validate
  • POST /drafts/{draftId}/compute
  • POST /drafts/{draftId}/commit

Deals

  • POST /deals
  • GET /deals/{dealId}
  • PATCH /deals/{dealId} (creates a new revision; optimistic locking)
  • GET /deals/{dealId}/revisions
  • GET /deals/{dealId}/snapshots
  • GET /snapshots/{snapshotId}/explain (optional)

CP / obligations

  • POST /deals/{dealId}/processing/start
  • GET /deals/{dealId}/obligations?asOf=YYYY-MM-DD
  • GET /deals/{dealId}/obligations/delta?fromSnapshot=...&toSnapshot=...
  • POST /deals/{dealId}/payments/ack
  • POST /deals/{dealId}/invoices/ack (optional)

Workflow state (deal-level, standardized per deal type)

Each deal type defines a strict enum field workflowState (shared across all consuming apps for that deal type).

  • Fetch allowed states and canonical mapping:
    • GET /models/{dealType}/versions/{version}/workflow
  • Render a picker constrained to that enum.
  • Send the selected value in your draft/deal payload as workflowState.

Input schema usage

  • Use GET /.../input-schema to render data-entry forms or validate client-side.
  • Schemas may reference library components in authoring, but deal programs serve a bundled schema appropriate for validation/rendering.

Calculations catalog

GET /.../calculations returns the list of metrics/outputs for the model version:

  • key
  • type (money/number/int/bool/object/string)
  • dependency hints (optional)

Important:

  • This is a catalog for UX and documentation.
  • The model does not embed an executable expression language.

Drafts are the primary workflow for interactive entry.

1) Create a draft

http
POST /drafts
Content-Type: application/json

{ "dealType": "touring_calcs_v1", "modelVersion": "1.0.0" }

2) Patch as the user types

http
PATCH /drafts/{draftId}
Content-Type: application/json

{ "terms": { "artistPct": 0.9 } }

3) Validate (lightweight)

http
POST /drafts/{draftId}/validate

4) Compute what-if (throttle/debounce)

http
POST /drafts/{draftId}/compute
Content-Type: application/json

{ "asOf": "2026-01-15" }

5) Commit (creates deal + revision + snapshot)

http
POST /drafts/{draftId}/commit

Deal update flow (optimistic locking)

Deal updates always create a new immutable revision.

  1. Read the deal:
http
GET /deals/{dealId}
  1. Update with If-Match (ETag from GET response):
http
PATCH /deals/{dealId}
If-Match: "<etag-from-get>"
Content-Type: application/json

{ "workflowState": "HOLD" }
json
{
  "type": "https://mdm.unitedtalent.com/api/errors/400-bad-request",
  "title": "Bad Request",
  "status": 400,
  "detail": "workflowState must be one of: DRAFT, OFFER_OUT, ...",
  "correlationId": "..."
}

Performance expectations (interactive UX)

  • PATCH /drafts/{id} and /validate should be fast enough for typing workflows.
  • compute can be throttled (e.g., run every 300–700ms).
  • Avoid calling compute on every keystroke; call on meaningful checkpoints.

Notes for Client Processing

  • CP should call /processing/start to pin a baseline snapshot.
  • CP should use obligation deltas classified as amendment vs correction (if enabled by the program).
  • CP acknowledgements (payments/ack, invoices/ack) must be idempotent and auditable.

Last updated: 2026-01-26

Confidential. For internal use only.