---
title: "Deploy Strategy"
method: POST
path: "/v1/deployments"
tags: ["deployments"]
---

# Deploy Strategy

`POST /v1/deployments`

## Request

- Base URL: `https://api.usekeel.io` (the document declares no server; this is the origin it was published from)
- URL: `https://api.usekeel.io/v1/deployments`
- Auth: none declared

## Headers

- `Authorization` string, nullable
- `X-Org-Id` string, nullable

## Request body

- DeployLiveRequest
  - `strategy_id` string, nullable
  - `managed_deployment` ManagedDeploymentAcceptance
    - `intent_token` string, required
    - `consent` ConsentAcknowledgment, required: Untrusted affirmative click; compared against a server-owned exact source.
      - `subject_kind` string, required
      - `subject_id` string, required
      - `subject_version` integer, required
      - `subject_hash` string, required
      - `document_type` string, required
      - `document_version` integer, required
      - `content_hash` string, required
  - `account_id` string, required
  - `schedule` string, nullable: Optional cron spelling; it must equal the selected commit's derived schedule.
  - `intent_token` string, nullable: Optional deploy-intent token when this deploy completes a handoff flow. Telemetry-only: a valid, matching token makes the deploy emit handoff_completed; it never gates or alters the deploy and carries no configuration (sizing is never accepted via API).
  - `tranching` object, nullable: Optional deployment-scoped tranche schedule block (Batch C): {"mode": "equal_split", "count": N, "window"?: M} or {"mode": "custom", "times": ["HH:MM", ...], "window"?: M}. Requires the org's 'tranching' execution grant (403 without it); an invalid block is a 422 with the exact reason. Absent/None deploys untranched — the config_json key is never written.
  - `execution_style` object, nullable: Optional deployment-scoped execution-style block: the closed-world maker document parse_execution_style_document accepts. Requires the org's 'maker' execution grant (403 without it); an invalid document is a 422 with the exact parse reason. Absent/None means CARRY the replaced deployment's style forward (or market on a first deploy) — market is always the absence of the block, never a style:'market' document, and an omitted key never disarms a carried style.
  - `attribution` DeployAttribution: Where a deploy came from, for telemetry only (S05 §3.4.6, IC-05-9; R-32). The one source today is the graduation carry-over: the page host reads ``source_run`` from its query and the live surface sends it back here. ``source_kind`` is closed, so an unknown kind is a 422 rather than a silently dropped key. The deploy route validates nothing else about it and no gate reads it; S07's reader (IC-07-6) owns the event it feeds.
    - `source_kind` 'graduation', required
    - `source_run_id` string, required

## Response `201`

Successful Response

- union
  - ManagedDeploymentResponse: Positive managed activation projection; no artifact or config fields.
    - `kind` 'managed'
    - `deployment_id` string, required
    - `link_id` string, required
    - `offering_id` string, required
    - `account_id` string, required
    - `org_id` string, required
    - `status` string, required
    - `deployed_commit_id` string, required
    - `deployed_version_string` string, required
    - `schedule` string, required
    - `deployed_at` string, date-time, nullable, required
  - DeploymentResponse
    - `deployment_id` string, required
    - `strategy_id` string, required
    - `name` string, required
    - `status` string, required
    - `schedule` string, nullable
    - `evaluation_grid` EvaluationGrid: The candle closes a deployment's runs evaluate (UX-8). Closes sit at ``offset_minutes`` past 00:00 UTC and every ``period_minutes`` after it: the deployment's cron inverted under its persisted dispatch generation (``utils.schedule.evaluation_grid``), so a pre-arm cron that fires at 11:59 reads as the 12:00 close it evaluates.
      - `period_minutes` integer, required
      - `offset_minutes` integer, required
    - `source_hash` string, nullable
    - `s3_key` string, nullable
    - `org_id` string, nullable
    - `account_id` string, nullable
    - `deployed_at` string, nullable
    - `stopped_at` string, nullable
    - `created_at` string, nullable
    - `updated_at` string, nullable
    - `deployed_commit_id` string, nullable
    - `deployed_version_string` string, nullable
    - `config_id` string, nullable
    - `total_pnl` number, nullable
    - `position_count` integer, nullable
    - `venue` VenueBlock: Which venue a deployment or account runs on, and its money class. Paper Trading v2, S01 §3.10 / IC-01-9. ``capital_class`` is ``trading.accounts.capital_class`` (``real`` or ``practice``); ``code`` is the venue's ``trading.venues.code`` (``HL``, ``PAPER``). On a deployment whose ``account_id`` names no account row (no foreign key refuses one, ``V6.0__deployments.sql:16``) the block reads ``{code: null, capital_class: "real"}``: such a row predates paper and keeps its pre-paper meaning. Clients key on this block, never on a probe.
      - `code` string, nullable
      - `capital_class` string, required
    - `remaining` object, nullable
    - `universe_warnings` UniverseWarning[], nullable
      - `symbol` string, required
      - `reason` 'DELISTED' | 'STALE', required
      - `detail` string, required
    - `account_warnings` AccountWarning[], nullable
      - `kind` 'EQUITY_BELOW_VENUE_MINIMUM' | 'ORDERS_SKIPPED_MIN_NOTIONAL' | 'EXITS_BELOW_VENUE_MINIMUM' | 'POSITION_STRANDED_BELOW_MINIMUM', required
      - `account_value` number, required
      - `min_notional` number, required
      - `detail` string, required
      - `orders_skipped` integer, nullable
      - `orders_total` integer, nullable
      - `exits_skipped` integer, nullable
      - `window_days` integer, nullable
      - `exit_symbols` string[], nullable
    - `execution_style` 'market' | 'maker', nullable
    - `paused_reason` string, nullable
    - `paused_at` string, nullable
    - `tranching` object, nullable
    - `health` 'running' | 'degraded' | 'stalled' | 'stopped', nullable
    - `health_detail` HealthDetailResponse: IC-04-2's ``health_detail`` (S04 §3.10.2): the first predicate that matched, the count of most recent consecutive missing bars, the newest COMPLETE bar, and the bar label the current state began at.
      - `reason` 'consecutive_missing' | 'latest_eval_failed' | 'latest_execution_failed' | 'dispatch_exhausted' | 'execution_missing' | 'rail_blocked' | 'funding_stalled' | 'equity_stale' | 'failure_rate' | 'silence' | 'halted' | 'schedule_unreadable', nullable, required
      - `consecutive_missing` integer, required
      - `last_complete_at` string, date-time, nullable, required
      - `since` string, date-time, nullable, required
    - `parity` ParityBlock: IC-03-2: the record's latest non-day-0 snapshot, else its first day-0 row.
      - `residual_bps` number, nullable, required
      - `status` 'tracking' | 'drifting' | 'under_review', required
      - `window_start` string, date-time, nullable, required
      - `window_end` string, date-time, nullable, required
      - `as_of` string, date-time, nullable, required
      - `eval_count` integer, required
      - `meter_eligible` boolean, required
      - `day0_backtest_run_id` string, nullable, required
      - `is_day0` boolean, required
      - `paper_return_pct` number, nullable, required
      - `backtest_return_pct` number, nullable, required
    - `graduation` GraduationBlock: IC-03-5: the graduation criteria state, computed on read. ``record`` and ``carry_over`` are null only for a deployment with no deployed commit (the record has no commit to name).
      - `ready` boolean, required
      - `ready_since` string, date-time, nullable, required
      - `nudged_at` string, date-time, nullable, required
      - `evaluated_at` string, date-time, required
      - `record` GraduationRecord, required: IC-03-5 ``record``: the record the criteria run over (R-27).
        - `started_at` string, date-time, required
        - `commit_id` string, required
        - `commit_seq` integer, required
        - `commit_changed_at` string, date-time, nullable, required
      - `thresholds` GraduationThresholds, required: IC-03-5 ``thresholds``: frozen at create from the defaults version (IC-03-6).
        - `min_age_days` integer, required
        - `min_evals` integer, required
        - `parity_band_bps` number, required
        - `backtest_max_dd_pct` number, nullable, required
        - `dd_floor_pending` boolean, required
        - `defaults_version` integer, required
      - `criteria` GraduationCriteria, required
        - `age` AgeCriterion, required
          - `met` boolean, required
          - `days` integer, required
          - `required_days` integer, required
        - `evals` EvalsCriterion, required
          - `met` boolean, required
          - `count` integer, required
          - `required` integer, required
        - `parity` ParityCriterion, required
          - `met` boolean, required
          - `residual_bps` number, nullable, required
          - `band_bps` number, required
          - `as_of` string, date-time, nullable, required
          - `eval_count` integer, required
          - `meter_eligible` boolean, required
          - `stale` boolean, required
        - `drawdown` DrawdownCriterion, required: Both drawdowns are positive magnitudes; the floor is null while pending.
          - `met` boolean, required
          - `paper_max_dd_pct` number, nullable, required
          - `backtest_max_dd_pct` number, nullable, required
      - `carry_over` CarryOver, required: IC-03-5 ``carry_over`` (S03 §3.9.5, R-32): no simulated capital.
        - `strategy_id` string, required
        - `commit_id` string, required
        - `schedule` string, nullable, required
        - `source_paper_deployment_id` string, required
        - `head_commit_id` string, required
        - `commit_ahead` boolean, required
        - `commit_seq` integer, required
        - `head_commit_seq` integer, required
        - `simulated_capital` string, nullable
        - `min_order_notional` string, nullable
    - `money_freshness` MoneyFreshness: Coverage state of the money facts behind a performance read (spec 04 §5.1, M4). Freshness is part of the answer: the number beside this block is only as fresh as the capture coverage that produced its inputs, and this block says exactly how fresh — * ``COVERED`` — coverage reaches the requested interval's end; ``fresh_as_of`` is the weakest fact class's reach. * ``SYNCING`` — the interval is managed and post-epoch but coverage has not reached its end yet; ``synced_through`` is how far it has (null when no coverage row speaks for the interval at all — absence never reads as fresh). * ``LEGACY`` — the interval predates the account's first coverage row (the epoch cutover): pre-capture history, served ungated but labeled. Until the capture lane goes live, every account reads this. * ``UNMANAGED`` — the interval overlaps no managed window; strategy performance is not defined there. Phase 1 labels only — no numeric field elsewhere in the response changes because of this block.
      - `state` 'COVERED' | 'SYNCING' | 'LEGACY' | 'UNMANAGED', required
      - `fresh_as_of` string, nullable
      - `synced_through` string, nullable
    - `serving_warnings` object[], nullable
    - `known_issues` KnownIssueRef[], nullable
      - `id` string, required
      - `summary` string, required
    - `live_window_warnings` LiveWindowWarning[], nullable
      - `code` 'LIVE_WINDOW_SHORTER_THAN_TRADES', required
      - `message` string, required
      - `backtest_run_id` string, required

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/usekeel/apis/keel-api.md) · [All operations](https://skmtc.dev/usekeel/apis/keel-api/llms.txt) · [OpenAPI document](https://skmtc.dev/usekeel/apis/keel-api/revisions/3191ca10b0ab?raw)
