{
	"openapi": "3.0.3",
	"info": {
		"title": "Purple Engine API",
		"version": "1.0.0",
		"description": "Unified fintech API for Purple brands (Axiory, Purple Trading, Fintokei) and third-party applications.\n\nEach business unit is served by its own gateway host; on production, Axiory's is purple-engine.axiory.com. The host selects the gateway and the services behind it; the brand in the access token does not.\n\nThe gateway refuses a call before any service sees it with 401 or 403 and an `error.code`, among them `TOKEN_EXPIRED` (renew or sign in again), `SCOPE_INSUFFICIENT` (the app lacks the permission, or its sign-in predates it), `ROUTE_NOT_CONFIGURED` (the operation is turned off for the app), `PARAM_NOT_PERMITTED` (an argument outside the app's filter), `APP_NOT_OWNER` (a personal app signed in with another brand account than its owner) and `APP_INACTIVE` (the app was revoked)."
	},
	"servers": [
		{
			"url": "https://purple-engine-axi-plt-1455.murban.personal.purple-lab.dev",
			"description": "Purple Engine API"
		}
	],
	"paths": {
		"/health": {
			"get": {
				"summary": "Health check",
				"operationId": "getHealth",
				"tags": [
					"system"
				],
				"security": [],
				"responses": {
					"200": {
						"description": "Service is healthy",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"status": {
											"type": "string",
											"enum": [
												"ok"
											]
										}
									}
								}
							}
						}
					}
				}
			}
		},
		"/v1/app-info": {
			"get": {
				"summary": "App metadata for OIDC consent screen",
				"description": "Public endpoint (no auth, no API key). Returns the third-party app's name, description, and capabilities so the brand's consent screen can render the approval flow. Anti-enumeration: malformed, unknown, and fully-inactive `app_id` values all return the same 200 shape with `name: ''` and `capabilities: []`. Pair with the WAF rule `AppInfoRateLimit` (100 req/min/IP).",
				"operationId": "getAppInfo",
				"tags": [
					"public"
				],
				"security": [],
				"parameters": [
					{
						"name": "app_id",
						"in": "query",
						"required": true,
						"description": "Application identifier from the App Registry.",
						"schema": {
							"type": "string",
							"pattern": "^[a-zA-Z0-9._-]+$"
						}
					}
				],
				"responses": {
					"200": {
						"description": "App metadata. `capabilities.length === 0` means unknown / invalid / deactivated — consent screen MUST NOT render the approve button.",
						"headers": {
							"Cache-Control": {
								"schema": {
									"type": "string"
								},
								"description": "public, max-age=300"
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/AppInfo"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal error (DynamoDB / engine-internal failure). Real outages are NOT suppressed into the empty-200 shape.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/requests/{requestId}": {
			"get": {
				"summary": "Read the status of an asynchronous request",
				"description": "Returns the status of an asynchronous request that the calling app created for the calling user, on either environment. Needs no scope: a request enters an app's namespace only through a scoped create call, and a request outside the caller's namespace answers the same 404 as an unknown id. Every `202` from an asynchronous endpoint names this URL in its `Location` header.",
				"operationId": "getRequestStatus",
				"tags": [
					"requests"
				],
				"parameters": [
					{
						"name": "requestId",
						"in": "path",
						"required": true,
						"description": "The `requestId` an asynchronous endpoint returned in its `202` body.",
						"schema": {
							"type": "string"
						}
					}
				],
				"responses": {
					"200": {
						"description": "The request's current status.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/RequestStatusResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "Unknown request, or one the caller did not create.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/fix-credentials": {
			"get": {
				"operationId": "readFixCredentials",
				"summary": "Check whether a cTrader trading account has an investor password",
				"description": "Pure, idempotent check of whether an investor password is stored for the given (serverId, traderId, env) composite trader key — safe to call on every connect. No broker call, no KMS call, no DDB write. Returns `{ status: \"stored\", provisionedAt }` (never the password) when a password exists, or `{ status: \"none\" }` when none does (the caller then provisions). Supported for cTrader accounts only (MT4/MT5/YourBourse → 422). The ownership gate verifies the engine-issued identity envelope (brandClientId) against the CRM crosswalk and report-server trader row; an unknown or unowned account returns 403 so existence is never leaked.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "FixCredentialsReadLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "serverId",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "traderId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"demo",
								"live"
							]
						},
						"required": true,
						"name": "env",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Whether an investor password is stored",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/FixCredentialsReadResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal (or unknown)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5/YourBourse not supported)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Identity/account lookup backend unavailable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/fix-credentials/provision": {
			"post": {
				"operationId": "provisionFixCredentials",
				"summary": "Provision (create-if-absent) the investor password for a cTrader trading account",
				"description": "Create-if-absent provisioning of the investor password for the given (serverId, traderId, env) composite trader key. When no password exists, uses the caller-supplied `password` if present (else mints one), sets it at the broker via Fintech (cTrader changePassword), encrypts it with KMS, persists the ciphertext, and returns `{ status: \"provisioned\", provisionedAt }` — never the password. A supplied password must satisfy the investor-password policy (8–16 chars, mixed case + digit + symbol, no whitespace) or is rejected with 400. When a password already exists, returns 409 with no broker write (a supplied password never overwrites an existing one). There is no force/override or rotation path. Supported for cTrader accounts only (MT4/MT5/YourBourse → 422). Ownership is verified per the identity envelope (brandClientId) and re-checked against a fresh trader-row read on every acting step. A concurrent provision for the same account returns 503.",
				"x-purple-target": {
					"type": "sync-sfn",
					"resource": "FixCredentialsProvisionSfn"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/FixCredentialsProvisionRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Investor password provisioned (not returned)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/FixCredentialsProvisionResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal (or unknown)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"409": {
						"description": "A password is already provisioned for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5/YourBourse not supported)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Concurrent provisioning in progress or recent failure; retry after lease window",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/credentials/ctrader": {
			"get": {
				"operationId": "readDemoFixCredentials",
				"summary": "Check whether one of the caller's demo cTrader accounts has an investor password",
				"description": "Pure, idempotent check of whether an investor password is stored for the account the accountId names — safe to call on every connect. No broker call, no KMS call, no DDB write. Returns `{ status: \"stored\", provisionedAt }` when a password exists, or `{ status: \"none\" }` when none does (the caller then provisions). The password itself is never returned. The account is resolved and its scope checked before the store is read. Supported for cTrader accounts only (MT4/MT5/YourBourse → 422).",
				"x-purple-target": {
					"type": "lambda",
					"resource": "FixCredentialsReadLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Whether an investor password is stored",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/FixCredentialsReadResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, or the forwarded scopes do not cover its credentials",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not a cTrader account (MT4/MT5/YourBourse not supported), or the request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Account data or account identifiers unavailable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			},
			"post": {
				"operationId": "provisionDemoFixCredentials",
				"summary": "Provision (create-if-absent) an investor password for one of the caller's demo cTrader accounts",
				"description": "Create-if-absent provisioning of the investor password for the account the accountId names. When no password exists, uses the caller-supplied `password` if present (else mints one), sets it at the broker via Fintech (cTrader changePassword), encrypts it with KMS, persists the ciphertext, and returns `{ status: \"provisioned\", provisionedAt }` — never the password. A supplied password must satisfy the investor-password policy (8–16 chars, mixed case + digit + symbol, no whitespace) or is rejected with 400. When a password already exists, returns 409 with no broker write (a supplied password never overwrites an existing one). There is no force/override or rotation path. The account is resolved and its scope checked before anything is issued, and re-checked against a fresh trader-row read on every acting step. Supported for cTrader accounts only (MT4/MT5/YourBourse → 422). A concurrent provision for the same account returns 503.",
				"x-purple-target": {
					"type": "sync-sfn",
					"resource": "FixCredentialsProvisionSfn"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/FixCredentialsStageProvisionRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Investor password provisioned (not returned)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/FixCredentialsProvisionResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, or the forwarded scopes do not cover its credentials",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"409": {
						"description": "A password is already provisioned for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not a cTrader account (MT4/MT5/YourBourse not supported), or the request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Concurrent provisioning in progress or recent failure (retry after the lease window), account data or account identifiers unavailable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/credentials/ctrader": {
			"get": {
				"operationId": "readLiveFixCredentials",
				"summary": "Check whether one of the caller's live cTrader accounts has an investor password",
				"description": "Pure, idempotent check of whether an investor password is stored for the account the accountId names — safe to call on every connect. No broker call, no KMS call, no DDB write. Returns `{ status: \"stored\", provisionedAt }` when a password exists, or `{ status: \"none\" }` when none does (the caller then provisions). The password itself is never returned. The account is resolved and its scope checked before the store is read. Supported for cTrader accounts only (MT4/MT5/YourBourse → 422).",
				"x-purple-target": {
					"type": "lambda",
					"resource": "FixCredentialsReadLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Whether an investor password is stored",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/FixCredentialsReadResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, or the forwarded scopes do not cover its credentials",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not a cTrader account (MT4/MT5/YourBourse not supported), or the request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Account data or account identifiers unavailable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			},
			"post": {
				"operationId": "provisionLiveFixCredentials",
				"summary": "Provision (create-if-absent) an investor password for one of the caller's live cTrader accounts",
				"description": "Create-if-absent provisioning of the investor password for the account the accountId names. When no password exists, uses the caller-supplied `password` if present (else mints one), sets it at the broker via Fintech (cTrader changePassword), encrypts it with KMS, persists the ciphertext, and returns `{ status: \"provisioned\", provisionedAt }` — never the password. A supplied password must satisfy the investor-password policy (8–16 chars, mixed case + digit + symbol, no whitespace) or is rejected with 400. When a password already exists, returns 409 with no broker write (a supplied password never overwrites an existing one). There is no force/override or rotation path. The account is resolved and its scope checked before anything is issued, and re-checked against a fresh trader-row read on every acting step. Supported for cTrader accounts only (MT4/MT5/YourBourse → 422). A concurrent provision for the same account returns 503.",
				"x-purple-target": {
					"type": "sync-sfn",
					"resource": "FixCredentialsProvisionSfn"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/FixCredentialsStageProvisionRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Investor password provisioned (not returned)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/FixCredentialsProvisionResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, or the forwarded scopes do not cover its credentials",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"409": {
						"description": "A password is already provisioned for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not a cTrader account (MT4/MT5/YourBourse not supported), or the request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Concurrent provisioning in progress or recent failure (retry after the lease window), account data or account identifiers unavailable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-accounts": {
			"get": {
				"operationId": "getAccountsByTraderEmail",
				"summary": "List the caller's trading accounts",
				"description": "Returns every trading account associated with the authenticated caller: both report-server instances (demo + live) plus the caller's YourBourse accounts, in one array. A YourBourse account carries `platform: yourbourse` and an identity tuple derived from a reserved server id, so it cannot collide with a report-server account's. Identity is resolved via the engine-supplied brandClientId → CRM crosswalk. Empty result (no CRM row, or no trading accounts) returns 200 with `accounts: []`. When the YourBourse store cannot be read but the report server answered, the report-server accounts are returned and the failure is logged — the 503 below still means both report-server instances are unreachable.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetAccountsByTraderEmailLambda"
				},
				"responses": {
					"200": {
						"description": "Accounts for the caller (possibly empty array)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/GetAccountsByTraderEmailResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error (malformed identity fields)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Both report-server instances unreachable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/accounts": {
			"get": {
				"operationId": "getDemoAccounts",
				"summary": "List the caller's demo trading accounts",
				"description": "Returns the authenticated caller's demo trading accounts only, each with the opaque accountId the other /v1/trading-account/demo/* routes address it by. The caller's YourBourse accounts are included only where this deployment serves them on this stage. Identity is resolved via the engine-supplied brandClientId → CRM crosswalk; no caller-supplied input is read. Empty result (no CRM row, or no accounts on this stage) returns 200 with `accounts: []`. When the YourBourse store cannot be read but the report server answered, the report-server accounts are returned and the failure is logged.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetAccountsByTraderEmailLambda"
				},
				"responses": {
					"200": {
						"description": "Accounts for the caller on this stage (possibly empty)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/GetStageAccountsResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error (malformed identity or envelope fields)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "The forwarded scopes do not hold purple-engine/trading-account.demo.accounts.read",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "The request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "This stage's report server or account identifiers unavailable, or the engine relied on a default this service does not apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			},
			"post": {
				"operationId": "createDemoTradingAccount",
				"summary": "Open a demo Axiory trading account on cTrader or YourBourse",
				"description": "Async capability that opens a demo trading account for the end-user resolved from the verified envelope (never a request field). `Idempotency-Key` is a required HTTP header (consumed by the engine async proxy, never seen by this service). Returns 202 immediately with a `Location` header naming the status path of the request; poll that path, or receive a Standard-Webhooks-v1 signed callback at `callbackUrl` when the app takes callbacks. The status and callback payloads are those of the old account-provisioning routes.",
				"x-purple-target": {
					"type": "async-sfn",
					"resource": "AccountProvisioningDemoSfn"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateDemoAccountRequestBody"
							}
						}
					}
				},
				"responses": {
					"202": {
						"description": "Request accepted; account opening proceeds asynchronously. The `Location` header carries the status path of the request.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/AccountProvisioningAcceptedResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/accounts": {
			"get": {
				"operationId": "getLiveAccounts",
				"summary": "List the caller's live trading accounts",
				"description": "Returns the authenticated caller's live trading accounts only, each with the opaque accountId the other /v1/trading-account/live/* routes address it by. The caller's YourBourse accounts are included only where this deployment serves them on this stage. Identity is resolved via the engine-supplied brandClientId → CRM crosswalk; no caller-supplied input is read. Empty result (no CRM row, or no accounts on this stage) returns 200 with `accounts: []`. When the YourBourse store cannot be read but the report server answered, the report-server accounts are returned and the failure is logged.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetAccountsByTraderEmailLambda"
				},
				"responses": {
					"200": {
						"description": "Accounts for the caller on this stage (possibly empty)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/GetStageAccountsResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error (malformed identity or envelope fields)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "The forwarded scopes do not hold purple-engine/trading-account.live.accounts.read",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "The request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "This stage's report server or account identifiers unavailable, or the engine relied on a default this service does not apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			},
			"post": {
				"operationId": "createLiveTradingAccount",
				"summary": "Open a live Axiory trading account under a corporate cTID alias",
				"description": "Async capability that opens a live trading account for the end-user resolved from the verified envelope (never a request field). `Idempotency-Key` is a required HTTP header (consumed by the engine async proxy, never seen by this service). Returns 202 immediately with a `Location` header naming the status path of the request; poll that path, or receive a Standard-Webhooks-v1 signed callback at `callbackUrl` when the app takes callbacks. The status and callback payloads are those of the old account-provisioning routes.",
				"x-purple-target": {
					"type": "async-sfn",
					"resource": "AccountProvisioningLiveSfn"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateLiveAccountRequestBody"
							}
						}
					}
				},
				"responses": {
					"202": {
						"description": "Request accepted; account opening proceeds asynchronously. The `Location` header carries the status path of the request.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/AccountProvisioningAcceptedResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/trades": {
			"get": {
				"operationId": "getAccountTrades",
				"summary": "List trades for a caller-owned trading account",
				"description": "Returns a cursor-paginated list of trades for the specified account. Ownership is verified against the caller's identity (brandClientId). Cursor is the last positionId from the previous page; omit for first page.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetAccountTradesLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "serverId",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "traderId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"demo",
								"live"
							]
						},
						"required": true,
						"name": "env",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"OPEN",
								"CLOSED",
								"ALL"
							]
						},
						"required": false,
						"name": "status",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true,
							"maximum": 100
						},
						"required": false,
						"name": "limit",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": false,
						"name": "cursor",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Paginated trades (possibly empty)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradesPage"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Account not owned by authenticated principal",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not served by this feature — report-server accounts only",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Report server unreachable, or ownership could not be established because an account source was unreadable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/transactions": {
			"get": {
				"operationId": "getAccountTransactions",
				"summary": "List transactions for a caller-owned trading account",
				"description": "Returns a cursor-paginated list of transactions for the specified account. type=balance returns balance-op transactions (transactionCodes \\ feeCodes); type=fee returns fee transactions; omit for all. Cursor is the last transactionId from the previous page.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetAccountTransactionsLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "serverId",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "traderId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"demo",
								"live"
							]
						},
						"required": true,
						"name": "env",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"balance",
								"fee"
							]
						},
						"required": false,
						"name": "type",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true,
							"maximum": 100
						},
						"required": false,
						"name": "limit",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": false,
						"name": "cursor",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Paginated transactions (possibly empty)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TransactionsPage"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Account not owned by authenticated principal",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not served by this feature — report-server accounts only",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Report server unreachable, or ownership could not be established because an account source was unreadable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/trades": {
			"get": {
				"operationId": "getDemoTrades",
				"summary": "List trades for one of the caller's demo accounts",
				"description": "Returns a cursor-paginated list of trades for the account the accountId names. Cursor is the last positionId from the previous page; omit for first page.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetAccountTradesLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"OPEN",
								"CLOSED",
								"ALL"
							],
							"default": "ALL"
						},
						"required": false,
						"name": "status",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true,
							"maximum": 100,
							"default": 20
						},
						"required": false,
						"name": "limit",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"opaque": true
						},
						"required": false,
						"name": "cursor",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Paginated trades (possibly empty)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradesPage"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, or the forwarded scopes do not cover it",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not served by this feature — report-server accounts only — or the request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Report server or account identifiers unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/transactions": {
			"get": {
				"operationId": "getDemoTransactions",
				"summary": "List transactions for one of the caller's demo accounts",
				"description": "Returns a cursor-paginated list of transactions for the account the accountId names. type=balance returns balance-op transactions; type=fee returns fee transactions; omit for all. Cursor is the last transactionId from the previous page.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetAccountTransactionsLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"balance",
								"fee"
							]
						},
						"required": false,
						"name": "type",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true,
							"maximum": 100,
							"default": 20
						},
						"required": false,
						"name": "limit",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"opaque": true
						},
						"required": false,
						"name": "cursor",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Paginated transactions (possibly empty)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TransactionsPage"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, or the forwarded scopes do not cover it",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not served by this feature — report-server accounts only — or the request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Report server or account identifiers unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/trades": {
			"get": {
				"operationId": "getLiveTrades",
				"summary": "List trades for one of the caller's live accounts",
				"description": "Returns a cursor-paginated list of trades for the account the accountId names. Cursor is the last positionId from the previous page; omit for first page.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetAccountTradesLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"OPEN",
								"CLOSED",
								"ALL"
							],
							"default": "ALL"
						},
						"required": false,
						"name": "status",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true,
							"maximum": 100,
							"default": 20
						},
						"required": false,
						"name": "limit",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"opaque": true
						},
						"required": false,
						"name": "cursor",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Paginated trades (possibly empty)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradesPage"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, or the forwarded scopes do not cover it",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not served by this feature — report-server accounts only — or the request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Report server or account identifiers unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/transactions": {
			"get": {
				"operationId": "getLiveTransactions",
				"summary": "List transactions for one of the caller's live accounts",
				"description": "Returns a cursor-paginated list of transactions for the account the accountId names. type=balance returns balance-op transactions; type=fee returns fee transactions; omit for all. Cursor is the last transactionId from the previous page.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetAccountTransactionsLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"balance",
								"fee"
							]
						},
						"required": false,
						"name": "type",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true,
							"maximum": 100,
							"default": 20
						},
						"required": false,
						"name": "limit",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"opaque": true
						},
						"required": false,
						"name": "cursor",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Paginated transactions (possibly empty)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TransactionsPage"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, or the forwarded scopes do not cover it",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is not served by this feature — report-server accounts only — or the request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Report server or account identifiers unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/account-provisioning/live": {
			"post": {
				"operationId": "createLiveAccount",
				"summary": "Open a live Axiory trading account under a corporate cTID alias",
				"description": "Async capability that bridges to the my-axiory live account-opening Step Function. Opens a cTrader account under the corporate `ctrader.ctid` alias while the account belongs to the end-user resolved from the verified envelope (never a request field). `Idempotency-Key` is a required HTTP header (consumed by the engine async proxy, never seen by this service) — retried requests with the same key never open a second account. Returns 202 immediately; completion is delivered later as a Standard-Webhooks-v1 signed callback to the (stripped) `callbackUrl`.",
				"x-purple-target": {
					"type": "async-sfn",
					"resource": "AccountProvisioningLiveSfn"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateLiveAccountRequest"
							}
						}
					}
				},
				"responses": {
					"202": {
						"description": "Request accepted; account opening proceeds asynchronously",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/AccountProvisioningAcceptedResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/account-provisioning/demo": {
			"post": {
				"operationId": "createDemoAccount",
				"summary": "Open a demo Axiory trading account on cTrader or YourBourse",
				"description": "Async capability that opens a demo trading account for the end-user resolved from the verified envelope (never a request field). With `platform: CTRADER` it bridges to the my-axiory demo account-opening Step Function and opens the account under the corporate `ctrader.ctid` alias; with `platform: YOURBOURSE` it calls the YourBourse Admin API directly and carries no options block. `Idempotency-Key` is a required HTTP header (consumed by the engine async proxy, never seen by this service) — retried requests with the same key never open a second account. Returns 202 immediately; completion is delivered later as a Standard-Webhooks-v1 signed callback to the (stripped) `callbackUrl`, with a payload discriminated by platform.",
				"x-purple-target": {
					"type": "async-sfn",
					"resource": "AccountProvisioningDemoSfn"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateDemoAccountRequest"
							}
						}
					}
				},
				"responses": {
					"202": {
						"description": "Request accepted; account opening proceeds asynchronously",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/AccountProvisioningAcceptedResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/account-provisioning/status": {
			"get": {
				"operationId": "getAccountProvisioningStatus",
				"summary": "Read the lifecycle status + result of an account-provisioning request",
				"description": "Pure, idempotent read of the status read-model for a previously-accepted request, by the `requestId` from the 202 response. Returns the current lifecycle state (PENDING while in flight; SUCCEEDED/FAILED once terminal) and, when terminal, the unified result. Access is scoped to the verified envelope: a request that does not belong to the caller's `{brand, brandClientId, consumer}` namespace returns an identical 404 to a non-existent one, so request ids cannot be enumerated. This is a convenience read-model — the authoritative completion signal is the engine-delivered callback.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "AccountProvisioningStatusLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The engine request id returned in the 202 accepted response."
						},
						"required": true,
						"description": "The engine request id returned in the 202 accepted response.",
						"name": "requestId",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Current status and (when terminal) the unified result",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/AccountProvisioningStatusResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No such request for the authenticated principal (also returned when the request belongs to a different namespace — enumeration-safe)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/positions": {
			"get": {
				"operationId": "getTradingPositions",
				"summary": "List open positions for a caller-owned trading account",
				"description": "Open positions from the service-held FIX session. Creates the session on first use. stopLoss and takeProfit are nullable — an absent broker tag is null, never zero. `divergence` is a three-valued enum (new / matched / diverged) reporting whether local state agreed with the broker across a reconnect. `openedAt` is the original open time for a position known before a reconnect. `asOf` and `confirmedAt` are broker-confirmation times, not serve times. Volumes are in units, not lots.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "serverId",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "traderId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"demo",
								"live"
							]
						},
						"required": true,
						"name": "env",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"
						},
						"required": false,
						"name": "symbol",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Open positions",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingPositionsResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session connecting, reconciling, reconnecting, owned elsewhere, or its login held by an external client",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/orders": {
			"get": {
				"operationId": "getTradingOrders",
				"summary": "List orders for a caller-owned trading account",
				"description": "Orders from the service-held FIX session. Creates the session on first use. `status` defaults to `pending` — working orders, including partially filled ones — so an omitted `status` returns a FILTERED list; pass `status=all` for the terminal tail as well. Carries its own `complete` flag: false while the order snapshot is still settling or ended in a timeout, because a caller reading orders never sees the session document and would otherwise read a truncated list as authoritative. Volumes are in units.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "serverId",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "traderId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"demo",
								"live"
							]
						},
						"required": true,
						"name": "env",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"pending",
								"filled",
								"cancelled",
								"rejected",
								"all"
							],
							"default": "pending"
						},
						"required": false,
						"name": "status",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Orders",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingOrdersResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable in its current state",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			},
			"post": {
				"operationId": "placeTradingOrder",
				"summary": "Place an order on a caller-owned trading account",
				"description": "Requires an Idempotency-Key. Volume is in UNITS, not lots, matching the broker catalogue. LIMIT requires price, STOP requires stopPrice, GTD requires expireTime; MARKET accepts neither expireTime nor positionId. STOP_LIMIT is not offered — the broker does not support it. BRACKET-ORDER CHECK EXEMPTION: an order carrying a positionId that matches a KNOWN local position skips the position-size and open-position-count checks, because those checks exist to bound new exposure and a bracket order reduces it — applying every check uniformly would reject a protective stop-loss on an account already at its position limit. An UNRECOGNISED positionId grants no exemption and is checked as new exposure; `risk.bracketExemptionApplied` reports which happened. Every broker outcome for a message that was sent — including a reject, a cancel and an expiry — is a 200 carrying `execution.status`; `unknown` means no terminal report arrived in the wait budget, so verify with a read rather than resending. The service never answers a write with a 5xx once a message may have left the socket.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/PlaceTradingOrderRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Order accepted; see execution.status for the outcome. When the service did not answer inside the hop budget the body is the unknown-outcome partial: `execution.status` is `unknown` and no other field is present",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/PlaceTradingOrderRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, trade lock timeout, or Idempotency-Key reused with a different request",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or the broker refused the message as an order",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable, or the idempotency store is unavailable and the write failed closed; nothing was sent",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			},
			"patch": {
				"operationId": "modifyTradingOrder",
				"summary": "Modify a pending order on a caller-owned trading account",
				"description": "Requires an Idempotency-Key. Identify the order by orderId (the broker-assigned id) or by clOrdId; exactly one is needed. Volume is in units. The order id rides the body rather than the path.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/ModifyTradingOrderRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Modified order, or the unknown-outcome partial when the service did not answer inside the hop budget",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ModifyTradingOrderRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"404": {
						"description": "Unknown order for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or broker refusal",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			},
			"delete": {
				"operationId": "cancelTradingOrder",
				"summary": "Cancel a pending order on a caller-owned trading account",
				"description": "Requires an Idempotency-Key. Identify the order by orderId or clOrdId. The kill switch is still the first check: cancelling a bracket order is not de-risking, so no blanket exemption applies.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CancelTradingOrderRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Cancelled order, or the unknown-outcome partial when the service did not answer inside the hop budget",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CancelTradingOrderRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"404": {
						"description": "Unknown order for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or broker refusal",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/quote": {
			"get": {
				"operationId": "getTradingQuote",
				"summary": "Read one symbol quote for a caller-owned trading account",
				"description": "Subscribes the symbol on demand and serves the cached tick. `stale` is true when the tick is older than the freshness window. `confirmedAt` is the broker tick time. Subscriptions are capped per session; exceeding the cap is a validation error naming the limit.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "serverId",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "traderId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"demo",
								"live"
							]
						},
						"required": true,
						"name": "env",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"
						},
						"required": true,
						"name": "symbol",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Quote",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingQuoteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, unknown symbol, or subscription cap exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Quote connection not serviceable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/quotes": {
			"get": {
				"operationId": "getTradingQuotes",
				"summary": "Read several symbol quotes for a caller-owned trading account",
				"description": "Subscribes the requested symbols on demand, bounded by the per-session subscription cap, and serves cached ticks. Symbols with no tick yet are listed in `missing` rather than failing the batch.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "serverId",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "traderId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"demo",
								"live"
							]
						},
						"required": true,
						"name": "env",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": true,
						"name": "symbols",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Quotes",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingQuotesResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, unknown symbol, or subscription cap exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Quote connection not serviceable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/symbols": {
			"get": {
				"operationId": "getTradingSymbols",
				"summary": "List the tradable symbol catalogue for an account",
				"description": "The TRADABLE subset of the broker symbol catalogue for the server the matched account row names — a symbol the broker has disabled is absent from this list even though a position already open on it can still be read, priced and closed. NON-CREATING: needs no FIX session and never starts one, so polling it cannot resurrect an idle-evicted session. Volumes (lotSize, minVolume, maxVolume, volumeStep) are in units. minVolume and volumeStep are DERIVED as 0.01 lot wherever the broker export omits them, which is every row of both production catalogues today; maxVolume is always null because the broker publishes no per-symbol maximum.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "serverId",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "traderId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"demo",
								"live"
							]
						},
						"required": true,
						"name": "env",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": false,
						"name": "search",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": false,
						"name": "assetClass",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Symbol catalogue",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingSymbolsResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/session": {
			"get": {
				"operationId": "getTradingSession",
				"summary": "Read FIX session status for a caller-owned trading account",
				"description": "Per-connection status for the trade and quote legs. NON-CREATING: never connects, so health polling cannot resurrect idle-evicted sessions or re-claim logins nobody is trading — an absent or evicted session is 404, not a connect. Reports trading readiness and reconciliation completeness as SEPARATE flags: trading activates on the position snapshot alone, so tradingReady true with reconciliationComplete false is normal while orders settle. `positionSnapshotDefinitive` says whether the position snapshot ended on a definitive end-of-snapshot signal or on a fallback timer, in which case it may be truncated. A connection whose login was taken by an external client reports reason=login_taken_by_external_client, distinct from broker_unreachable and from converging, and is user-actionable.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "serverId",
						"in": "query"
					},
					{
						"schema": {
							"type": "integer",
							"minimum": 0,
							"exclusiveMinimum": true
						},
						"required": true,
						"name": "traderId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"demo",
								"live"
							]
						},
						"required": true,
						"name": "env",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Session status",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingSessionStatusResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"404": {
						"description": "No session held for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session owned by another task and that task could not be reached; retry — nothing about the session was changed",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/positions/close": {
			"post": {
				"operationId": "closeTradingPosition",
				"summary": "Close a position on a caller-owned trading account",
				"description": "Requires an Idempotency-Key. Omit volume to close the whole position; volume is in units. `position` is null when the close flattened it. Bracket orders linked to the position are cancelled automatically and listed in `cancelledLinkedOrders`. The position id rides the body rather than the path.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CloseTradingPositionRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Close accepted; see execution.status. When the service did not answer inside the hop budget the body is the unknown-outcome partial and carries no position or realisedPnl",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CloseTradingPositionRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"404": {
						"description": "Unknown position for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or broker refusal",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/positions/close-all": {
			"post": {
				"operationId": "closeAllTradingPositions",
				"summary": "Close every open position on a caller-owned trading account",
				"description": "Requires an Idempotency-Key. Optionally filtered by symbol. Partial failure is a 200 with per-position results in THREE buckets: `closed` (the broker confirmed a fill), `pending` (accepted, no terminal report inside the wait budget — it may well have closed) and `failed` (refused). Two buckets are insufficient: folding `pending` into `closed` reports a close that may not have happened, and folding it into `failed` invites a second close of a position that is already flat. A retried close-all resumes rather than closing twice.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CloseAllTradingPositionsRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Per-position results in three buckets. When the service did not answer inside the hop budget the body is instead the unknown-outcome partial — no results and no summary, because this hop never learnt what any leg did",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CloseAllTradingPositionsRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, kill switch active, or risk check failed",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/session/reconnect": {
			"post": {
				"operationId": "reconnectTradingSession",
				"summary": "Reconnect the FIX session for a caller-owned trading account",
				"description": "Requires an Idempotency-Key, like every write route — though a reconnect is idempotent by nature, so the durable record behind it is exempt or scoped to seconds rather than kept for days, which would replay a stale acknowledgement to a legitimate reconnect an hour later. The consumer-safe session verb: a reconnect already in progress returns the same acknowledgement rather than restarting anything. With no session held it connects. It never resets the reconnect backoff of a session whose login an external client holds — that state is reported as a conflict instead, because reconnecting cannot win a login back and resetting the backoff would hammer it.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/ReconnectTradingSessionRequest"
							}
						}
					}
				},
				"responses": {
					"202": {
						"description": "Reconnect accepted",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ReconnectTradingSessionResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal, or unknown — one identical response for both, so account existence is never leaked. Also returned when the caller holds no scope matching the route and the account's environment",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "The login is held by an external client, or the session is owned elsewhere during failover",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/positions": {
			"get": {
				"operationId": "getDemoTradingPositions",
				"summary": "List open positions for a caller-owned trading account (demo)",
				"description": "Open positions from the service-held FIX session. Creates the session on first use. stopLoss and takeProfit are nullable — an absent broker tag is null, never zero. `divergence` is a three-valued enum (new / matched / diverged) reporting whether local state agreed with the broker across a reconnect. `openedAt` is the original open time for a position known before a reconnect. `asOf` and `confirmedAt` are broker-confirmation times, not serve times. Volumes are in units, not lots. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"
						},
						"required": false,
						"name": "symbol",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Open positions",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingPositionsResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session connecting, reconciling, reconnecting, owned elsewhere, or its login held by an external client",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/orders": {
			"get": {
				"operationId": "getDemoTradingOrders",
				"summary": "List orders for a caller-owned trading account (demo)",
				"description": "Orders from the service-held FIX session. Creates the session on first use. `status` defaults to `pending` — working orders, including partially filled ones — so an omitted `status` returns a FILTERED list; pass `status=all` for the terminal tail as well. Carries its own `complete` flag: false while the order snapshot is still settling or ended in a timeout, because a caller reading orders never sees the session document and would otherwise read a truncated list as authoritative. Volumes are in units. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"pending",
								"filled",
								"cancelled",
								"rejected",
								"all"
							],
							"default": "pending"
						},
						"required": false,
						"name": "status",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Orders",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingOrdersResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable in its current state",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			},
			"post": {
				"operationId": "placeDemoTradingOrder",
				"summary": "Place an order on a caller-owned trading account (demo)",
				"description": "Requires an Idempotency-Key. Volume is in UNITS, not lots, matching the broker catalogue. LIMIT requires price, STOP requires stopPrice, GTD requires expireTime; MARKET accepts neither expireTime nor positionId. STOP_LIMIT is not offered — the broker does not support it. BRACKET-ORDER CHECK EXEMPTION: an order carrying a positionId that matches a KNOWN local position skips the position-size and open-position-count checks, because those checks exist to bound new exposure and a bracket order reduces it — applying every check uniformly would reject a protective stop-loss on an account already at its position limit. An UNRECOGNISED positionId grants no exemption and is checked as new exposure; `risk.bracketExemptionApplied` reports which happened. Every broker outcome for a message that was sent — including a reject, a cancel and an expiry — is a 200 carrying `execution.status`; `unknown` means no terminal report arrived in the wait budget, so verify with a read rather than resending. The service never answers a write with a 5xx once a message may have left the socket. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/PlaceStageTradingOrderRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Order accepted; see execution.status for the outcome. When the service did not answer inside the hop budget the body is the unknown-outcome partial: `execution.status` is `unknown` and no other field is present",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/PlaceTradingOrderRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, trade lock timeout, or Idempotency-Key reused with a different request",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or the broker refused the message as an order; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable, or the idempotency store is unavailable and the write failed closed; nothing was sent; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			},
			"patch": {
				"operationId": "modifyDemoTradingOrder",
				"summary": "Modify a pending order on a caller-owned trading account (demo)",
				"description": "Requires an Idempotency-Key. Identify the order by orderId (the broker-assigned id) or by clOrdId; exactly one is needed. Volume is in units. The order id rides the body rather than the path. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/ModifyStageTradingOrderRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Modified order, or the unknown-outcome partial when the service did not answer inside the hop budget",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ModifyTradingOrderRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked. Also: Unknown order for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or broker refusal; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			},
			"delete": {
				"operationId": "cancelDemoTradingOrder",
				"summary": "Cancel a pending order on a caller-owned trading account (demo)",
				"description": "Requires an Idempotency-Key. Identify the order by orderId or clOrdId. The kill switch is still the first check: cancelling a bracket order is not de-risking, so no blanket exemption applies. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CancelStageTradingOrderRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Cancelled order, or the unknown-outcome partial when the service did not answer inside the hop budget",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CancelTradingOrderRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked. Also: Unknown order for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or broker refusal; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/quotes": {
			"get": {
				"operationId": "getDemoTradingQuotes",
				"summary": "Read several symbol quotes for a caller-owned trading account (demo)",
				"description": "Subscribes the requested symbols on demand, bounded by the per-session subscription cap, and serves cached ticks. Symbols with no tick yet are listed in `missing` rather than failing the batch. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": true,
						"name": "symbols",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Quotes",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingQuotesResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, unknown symbol, or subscription cap exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Quote connection not serviceable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/symbols": {
			"get": {
				"operationId": "getDemoTradingSymbols",
				"summary": "List the tradable symbol catalogue for an account (demo)",
				"description": "The TRADABLE subset of the broker symbol catalogue for the server the matched account row names — a symbol the broker has disabled is absent from this list even though a position already open on it can still be read, priced and closed. NON-CREATING: needs no FIX session and never starts one, so polling it cannot resurrect an idle-evicted session. Volumes (lotSize, minVolume, maxVolume, volumeStep) are in units. minVolume and volumeStep are DERIVED as 0.01 lot wherever the broker export omits them, which is every row of both production catalogues today; maxVolume is always null because the broker publishes no per-symbol maximum. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": false,
						"name": "search",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": false,
						"name": "assetClass",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Symbol catalogue",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingSymbolsResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/session": {
			"get": {
				"operationId": "getDemoTradingSession",
				"summary": "Read FIX session status for a caller-owned trading account (demo)",
				"description": "Per-connection status for the trade and quote legs. NON-CREATING: never connects, so health polling cannot resurrect idle-evicted sessions or re-claim logins nobody is trading — an absent or evicted session is 404, not a connect. Reports trading readiness and reconciliation completeness as SEPARATE flags: trading activates on the position snapshot alone, so tradingReady true with reconciliationComplete false is normal while orders settle. `positionSnapshotDefinitive` says whether the position snapshot ended on a definitive end-of-snapshot signal or on a fallback timer, in which case it may be truncated. A connection whose login was taken by an external client reports reason=login_taken_by_external_client, distinct from broker_unreachable and from converging, and is user-actionable. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Session status",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingSessionStatusResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked. Also: No session held for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session owned by another task and that task could not be reached; retry — nothing about the session was changed",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/positions/close": {
			"post": {
				"operationId": "closeDemoTradingPosition",
				"summary": "Close a position on a caller-owned trading account (demo)",
				"description": "Requires an Idempotency-Key. Omit volume to close the whole position; volume is in units. `position` is null when the close flattened it. Bracket orders linked to the position are cancelled automatically and listed in `cancelledLinkedOrders`. The position id rides the body rather than the path. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CloseStageTradingPositionRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Close accepted; see execution.status. When the service did not answer inside the hop budget the body is the unknown-outcome partial and carries no position or realisedPnl",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CloseTradingPositionRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked. Also: Unknown position for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or broker refusal; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/positions/close-all": {
			"post": {
				"operationId": "closeAllDemoTradingPositions",
				"summary": "Close every open position on a caller-owned trading account (demo)",
				"description": "Requires an Idempotency-Key. Optionally filtered by symbol. Partial failure is a 200 with per-position results in THREE buckets: `closed` (the broker confirmed a fill), `pending` (accepted, no terminal report inside the wait budget — it may well have closed) and `failed` (refused). Two buckets are insufficient: folding `pending` into `closed` reports a close that may not have happened, and folding it into `failed` invites a second close of a position that is already flat. A retried close-all resumes rather than closing twice. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CloseAllStageTradingPositionsRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Per-position results in three buckets. When the service did not answer inside the hop budget the body is instead the unknown-outcome partial — no results and no summary, because this hop never learnt what any leg did",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CloseAllTradingPositionsRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, kill switch active, or risk check failed; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/session/reconnect": {
			"post": {
				"operationId": "reconnectDemoTradingSession",
				"summary": "Reconnect the FIX session for a caller-owned trading account (demo)",
				"description": "Requires an Idempotency-Key, like every write route — though a reconnect is idempotent by nature, so the durable record behind it is exempt or scoped to seconds rather than kept for days, which would replay a stale acknowledgement to a legitimate reconnect an hour later. The consumer-safe session verb: a reconnect already in progress returns the same acknowledgement rather than restarting anything. With no session held it connects. It never resets the reconnect backoff of a session whose login an external client holds — that state is reported as a conflict instead, because reconnecting cannot win a login back and resetting the backoff would hammer it. The account is addressed by the opaque accountId the demo account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/ReconnectStageTradingSessionRequest"
							}
						}
					}
				},
				"responses": {
					"202": {
						"description": "Reconnect accepted",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ReconnectTradingSessionResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "The login is held by an external client, or the session is owned elsewhere during failover",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/positions": {
			"get": {
				"operationId": "getLiveTradingPositions",
				"summary": "List open positions for a caller-owned trading account (live)",
				"description": "Open positions from the service-held FIX session. Creates the session on first use. stopLoss and takeProfit are nullable — an absent broker tag is null, never zero. `divergence` is a three-valued enum (new / matched / diverged) reporting whether local state agreed with the broker across a reconnect. `openedAt` is the original open time for a position known before a reconnect. `asOf` and `confirmedAt` are broker-confirmation times, not serve times. Volumes are in units, not lots. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"
						},
						"required": false,
						"name": "symbol",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Open positions",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingPositionsResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session connecting, reconciling, reconnecting, owned elsewhere, or its login held by an external client",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/orders": {
			"get": {
				"operationId": "getLiveTradingOrders",
				"summary": "List orders for a caller-owned trading account (live)",
				"description": "Orders from the service-held FIX session. Creates the session on first use. `status` defaults to `pending` — working orders, including partially filled ones — so an omitted `status` returns a FILTERED list; pass `status=all` for the terminal tail as well. Carries its own `complete` flag: false while the order snapshot is still settling or ended in a timeout, because a caller reading orders never sees the session document and would otherwise read a truncated list as authoritative. Volumes are in units. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string",
							"enum": [
								"pending",
								"filled",
								"cancelled",
								"rejected",
								"all"
							],
							"default": "pending"
						},
						"required": false,
						"name": "status",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Orders",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingOrdersResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable in its current state",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			},
			"post": {
				"operationId": "placeLiveTradingOrder",
				"summary": "Place an order on a caller-owned trading account (live)",
				"description": "Requires an Idempotency-Key. Volume is in UNITS, not lots, matching the broker catalogue. LIMIT requires price, STOP requires stopPrice, GTD requires expireTime; MARKET accepts neither expireTime nor positionId. STOP_LIMIT is not offered — the broker does not support it. BRACKET-ORDER CHECK EXEMPTION: an order carrying a positionId that matches a KNOWN local position skips the position-size and open-position-count checks, because those checks exist to bound new exposure and a bracket order reduces it — applying every check uniformly would reject a protective stop-loss on an account already at its position limit. An UNRECOGNISED positionId grants no exemption and is checked as new exposure; `risk.bracketExemptionApplied` reports which happened. Every broker outcome for a message that was sent — including a reject, a cancel and an expiry — is a 200 carrying `execution.status`; `unknown` means no terminal report arrived in the wait budget, so verify with a read rather than resending. The service never answers a write with a 5xx once a message may have left the socket. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/PlaceStageTradingOrderRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Order accepted; see execution.status for the outcome. When the service did not answer inside the hop budget the body is the unknown-outcome partial: `execution.status` is `unknown` and no other field is present",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/PlaceTradingOrderRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, trade lock timeout, or Idempotency-Key reused with a different request",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or the broker refused the message as an order; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable, or the idempotency store is unavailable and the write failed closed; nothing was sent; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			},
			"patch": {
				"operationId": "modifyLiveTradingOrder",
				"summary": "Modify a pending order on a caller-owned trading account (live)",
				"description": "Requires an Idempotency-Key. Identify the order by orderId (the broker-assigned id) or by clOrdId; exactly one is needed. Volume is in units. The order id rides the body rather than the path. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/ModifyStageTradingOrderRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Modified order, or the unknown-outcome partial when the service did not answer inside the hop budget",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ModifyTradingOrderRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked. Also: Unknown order for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or broker refusal; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			},
			"delete": {
				"operationId": "cancelLiveTradingOrder",
				"summary": "Cancel a pending order on a caller-owned trading account (live)",
				"description": "Requires an Idempotency-Key. Identify the order by orderId or clOrdId. The kill switch is still the first check: cancelling a bracket order is not de-risking, so no blanket exemption applies. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CancelStageTradingOrderRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Cancelled order, or the unknown-outcome partial when the service did not answer inside the hop budget",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CancelTradingOrderRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked. Also: Unknown order for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or broker refusal; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/quotes": {
			"get": {
				"operationId": "getLiveTradingQuotes",
				"summary": "Read several symbol quotes for a caller-owned trading account (live)",
				"description": "Subscribes the requested symbols on demand, bounded by the per-session subscription cap, and serves cached ticks. Symbols with no tick yet are listed in `missing` rather than failing the batch. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": true,
						"name": "symbols",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Quotes",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingQuotesResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, unknown symbol, or subscription cap exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Quote connection not serviceable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/symbols": {
			"get": {
				"operationId": "getLiveTradingSymbols",
				"summary": "List the tradable symbol catalogue for an account (live)",
				"description": "The TRADABLE subset of the broker symbol catalogue for the server the matched account row names — a symbol the broker has disabled is absent from this list even though a position already open on it can still be read, priced and closed. NON-CREATING: needs no FIX session and never starts one, so polling it cannot resurrect an idle-evicted session. Volumes (lotSize, minVolume, maxVolume, volumeStep) are in units. minVolume and volumeStep are DERIVED as 0.01 lot wherever the broker export omits them, which is every row of both production catalogues today; maxVolume is always null because the broker publishes no per-symbol maximum. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": false,
						"name": "search",
						"in": "query"
					},
					{
						"schema": {
							"type": "string"
						},
						"required": false,
						"name": "assetClass",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Symbol catalogue",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingSymbolsResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/session": {
			"get": {
				"operationId": "getLiveTradingSession",
				"summary": "Read FIX session status for a caller-owned trading account (live)",
				"description": "Per-connection status for the trade and quote legs. NON-CREATING: never connects, so health polling cannot resurrect idle-evicted sessions or re-claim logins nobody is trading — an absent or evicted session is 404, not a connect. Reports trading readiness and reconciliation completeness as SEPARATE flags: trading activates on the position snapshot alone, so tradingReady true with reconciliationComplete false is normal while orders settle. `positionSnapshotDefinitive` says whether the position snapshot ended on a definitive end-of-snapshot signal or on a fallback timer, in which case it may be truncated. A connection whose login was taken by an external client reports reason=login_taken_by_external_client, distinct from broker_unreachable and from converging, and is user-actionable. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"parameters": [
					{
						"schema": {
							"type": "string",
							"minLength": 1,
							"description": "The opaque accountId the account list on this stage returned for the account"
						},
						"required": true,
						"description": "The opaque accountId the account list on this stage returned for the account",
						"name": "accountId",
						"in": "query"
					}
				],
				"responses": {
					"200": {
						"description": "Session status",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingSessionStatusResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked. Also: No session held for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session owned by another task and that task could not be reached; retry — nothing about the session was changed",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/positions/close": {
			"post": {
				"operationId": "closeLiveTradingPosition",
				"summary": "Close a position on a caller-owned trading account (live)",
				"description": "Requires an Idempotency-Key. Omit volume to close the whole position; volume is in units. `position` is null when the close flattened it. Bracket orders linked to the position are cancelled automatically and listed in `cancelledLinkedOrders`. The position id rides the body rather than the path. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CloseStageTradingPositionRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Close accepted; see execution.status. When the service did not answer inside the hop budget the body is the unknown-outcome partial and carries no position or realisedPnl",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CloseTradingPositionRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked. Also: Unknown position for this account",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, risk check failed, kill switch active, or broker refusal; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/positions/close-all": {
			"post": {
				"operationId": "closeAllLiveTradingPositions",
				"summary": "Close every open position on a caller-owned trading account (live)",
				"description": "Requires an Idempotency-Key. Optionally filtered by symbol. Partial failure is a 200 with per-position results in THREE buckets: `closed` (the broker confirmed a fill), `pending` (accepted, no terminal report inside the wait budget — it may well have closed) and `failed` (refused). Two buckets are insufficient: folding `pending` into `closed` reports a close that may not have happened, and folding it into `failed` invites a second close of a position that is already flat. A retried close-all resumes rather than closing twice. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CloseAllStageTradingPositionsRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Per-position results in three buckets. When the service did not answer inside the hop budget the body is instead the unknown-outcome partial — no results and no summary, because this hop never learnt what any leg did",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CloseAllTradingPositionsRouteResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "Session not serviceable, lock timeout, or Idempotency-Key reused",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Not a cTrader account, kill switch active, or risk check failed; or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"429": {
						"description": "Per-account order rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable or idempotency store down; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/live/session/reconnect": {
			"post": {
				"operationId": "reconnectLiveTradingSession",
				"summary": "Reconnect the FIX session for a caller-owned trading account (live)",
				"description": "Requires an Idempotency-Key, like every write route — though a reconnect is idempotent by nature, so the durable record behind it is exempt or scoped to seconds rather than kept for days, which would replay a stale acknowledgement to a legitimate reconnect an hour later. The consumer-safe session verb: a reconnect already in progress returns the same acknowledgement rather than restarting anything. With no session held it connects. It never resets the reconnect backoff of a session whose login an external client holds — that state is reported as a conflict instead, because reconnecting cannot win a login back and resetting the backoff would hammer it. The account is addressed by the opaque accountId the live account list returned; an account of the other stage is never served on this route.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "TradingExecutionLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/ReconnectStageTradingSessionRequest"
							}
						}
					}
				},
				"responses": {
					"202": {
						"description": "Reconnect accepted",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ReconnectTradingSessionResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error, or Idempotency-Key missing",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, the forwarded scopes do not cover it, or it is outside the restrictions the request carries — one identical response for all of them, so account existence is never leaked",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"409": {
						"description": "The login is held by an external client, or the session is owned elsewhere during failover",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"422": {
						"description": "Account exists but is not a cTrader account (MT4/MT5 not supported); or the request carries a restriction this route cannot apply, or a value it cannot resolve",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Broker unreachable; or account identifiers are unavailable, ownership could not be established because an account source was unreadable, or the engine relied on a default this service no longer applies",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TradingExecutionError"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/access-token": {
			"post": {
				"operationId": "issueAccountAccessToken",
				"summary": "Issue a client-API credential for a caller-owned trading account",
				"description": "Mints, through the broker's admin API, a credential the broker's own client API accepts for the given (serverId, traderId, env) trading account, and returns it together with the client API address to use it at. One route serves every platform this domain resolves accounts for; a request naming an account on a platform this route cannot serve is refused (422) rather than routed to one. Ownership is resolved from the caller's own account list (KTD1) against the identity envelope alone — the request body names the account, never who is asking. A request naming an account the caller does not hold answers identically to one naming an account that does not exist, so this route cannot be used to discover which accounts exist.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "IssueAccountAccessTokenLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AccountAccessTokenRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Credential issued: the two signing parts, the broker's own identifier for the credential, its kind, when it stops working, and the client API address",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/AccountAccessTokenResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Requested (serverId, traderId, env) not owned by the authenticated principal. The same refusal also answers an account that does not exist, and an identity tuple that resolves to more than one account, so the route cannot be used to discover which accounts exist.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account exists, is the caller’s, and is on a platform this route does not serve. The body stays generic; the platform is recorded internally, not returned, because the owner already sees it in their own account list.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Service unavailable: either the account source is degraded and the requested account could not be confirmed as the caller's, or the outbound broker budget this route shares with account provisioning is spent for this stage.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-account/demo/credentials/yourbourse": {
			"post": {
				"operationId": "issueDemoAccessToken",
				"summary": "Issue a client-API credential for one of the caller's demo accounts",
				"description": "Mints, through the broker's admin API, a credential the broker's own client API accepts for the demo account the accountId names, and returns it together with the client API address to use it at. YourBourse accounts only: an account on another platform is refused (422), and only after it has been confirmed as the caller's and in scope.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "IssueAccountAccessTokenLambda"
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/StageAccountAccessTokenRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Credential issued: the two signing parts, the broker's own identifier for the credential, its kind, when it stops working, and the client API address",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/AccountAccessTokenResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No account of the caller on this stage answers to this accountId, or the forwarded scopes do not cover it. The same answer for an id that does not decode, carries another brand or stage, or names an account the caller does not hold, so the route cannot be used to discover which accounts exist.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "Account is the caller’s and in scope, and is on a platform this route does not serve; or the request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "Service unavailable: the account source or account identifiers are degraded, the outbound broker budget this route shares with account provisioning is spent for this stage, or the engine relied on a default this service does not apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		},
		"/v1/trading-user": {
			"get": {
				"operationId": "getTradingUser",
				"summary": "Get the caller's own CRM customer record",
				"description": "Returns the authenticated caller's own CRM customer record, resolved via the engine-supplied brandClientId. No caller-supplied id, email, or key is read or trusted. A valid caller with no CRM row receives a 404.",
				"x-purple-target": {
					"type": "lambda",
					"resource": "GetTradingUserLambda"
				},
				"responses": {
					"200": {
						"description": "The caller's CRM record",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/GetTradingUserResponse"
								}
							}
						}
					},
					"400": {
						"description": "Validation error (malformed identity fields)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"401": {
						"description": "Unauthorized",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"403": {
						"description": "Forbidden",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"description": "No CRM record exists for the caller",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"422": {
						"description": "The request carries a restriction this route cannot apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"500": {
						"description": "Internal Server Error",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"503": {
						"description": "CRM datastore unreachable, or the engine relied on a default this service does not apply",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					}
				}
			}
		}
	},
	"components": {
		"securitySchemes": {
			"apiKey": {
				"type": "apiKey",
				"in": "header",
				"name": "x-api-key"
			},
			"bearerAuth": {
				"type": "http",
				"scheme": "bearer",
				"bearerFormat": "JWT"
			}
		},
		"schemas": {
			"ErrorResponse": {
				"type": "object",
				"required": [
					"error"
				],
				"properties": {
					"error": {
						"type": "object",
						"required": [
							"code",
							"message"
						],
						"properties": {
							"code": {
								"type": "string"
							},
							"message": {
								"type": "string"
							},
							"requestId": {
								"type": "string"
							}
						}
					}
				}
			},
			"AppInfo": {
				"type": "object",
				"required": [
					"appId",
					"name",
					"capabilities"
				],
				"properties": {
					"appId": {
						"type": "string",
						"description": "Echoed `app_id` for known apps. Empty string when the request was malformed."
					},
					"name": {
						"type": "string",
						"description": "Display name for the consent screen. Empty string for unknown / invalid / deactivated apps (sentinel)."
					},
					"description": {
						"type": "string"
					},
					"capabilities": {
						"type": "array",
						"description": "Per-scope consent disclosures. Empty array for unknown / invalid / deactivated apps.",
						"items": {
							"type": "object",
							"required": [
								"scope",
								"label",
								"riskLevel"
							],
							"properties": {
								"scope": {
									"type": "string"
								},
								"label": {
									"type": "string"
								},
								"riskLevel": {
									"type": "string",
									"enum": [
										"standard",
										"high"
									]
								},
								"riskWarning": {
									"type": "string"
								}
							}
						}
					}
				}
			},
			"RequestStatusResponse": {
				"type": "object",
				"properties": {
					"requestId": {
						"type": "string"
					},
					"operation": {
						"type": "string",
						"enum": [
							"accounts.create"
						],
						"description": "The capability that created the request: the `accounts.create` scope."
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						],
						"description": "The environment the request was created on."
					},
					"status": {
						"$ref": "#/components/schemas/AccountProvisioningStatusState"
					},
					"platform": {
						"$ref": "#/components/schemas/DemoAccountPlatform"
					},
					"result": {
						"$ref": "#/components/schemas/AccountProvisioningStatusResult"
					},
					"updatedAt": {
						"type": "string",
						"description": "ISO timestamp of the last status transition."
					}
				},
				"required": [
					"requestId",
					"operation",
					"env",
					"status",
					"updatedAt"
				]
			},
			"AccountProvisioningStatusState": {
				"type": "string",
				"enum": [
					"PENDING",
					"SUCCEEDED",
					"FAILED"
				]
			},
			"DemoAccountPlatform": {
				"type": "string",
				"enum": [
					"CTRADER",
					"YOURBOURSE"
				],
				"description": "Target trading platform for a demo account. `CTRADER` bridges to my-axiory and requires the `ctrader` options block; `YOURBOURSE` calls the YourBourse Admin API directly and carries no options block of its own."
			},
			"AccountProvisioningStatusResult": {
				"type": "object",
				"properties": {
					"callbackStatus": {
						"type": "string",
						"enum": [
							"success",
							"error"
						]
					},
					"callbackPayload": {
						"type": "object",
						"additionalProperties": {
							"nullable": true
						},
						"description": "Completion payload, discriminated by the platform the request was opened on. On a cTrader success: the unified account fields + echoed ctid/correlationId; on a cTrader error: the failure code plus an `accountExists` marker (opened-but-failed vs not-opened) + best-effort echoed ctid/correlationId. On a YourBourse success: the account fields YourBourse returns, with no alias field; on a YourBourse error: the failure code plus a three-state `accountOutcome` (created | not_created | unknown) and the account number when one is known. Present on both success and error."
					},
					"error": {
						"type": "object",
						"properties": {
							"code": {
								"type": "string"
							},
							"message": {
								"type": "string"
							}
						},
						"required": [
							"code",
							"message"
						],
						"description": "Typed failure code + human-readable cause. Present on error."
					}
				},
				"required": [
					"callbackStatus"
				]
			},
			"FixCredentialsReadResponse": {
				"oneOf": [
					{
						"$ref": "#/components/schemas/FixCredentialsStored"
					},
					{
						"$ref": "#/components/schemas/FixCredentialsNone"
					}
				],
				"discriminator": {
					"propertyName": "status",
					"mapping": {
						"stored": "#/components/schemas/FixCredentialsStored",
						"none": "#/components/schemas/FixCredentialsNone"
					}
				}
			},
			"FixCredentialsStored": {
				"type": "object",
				"properties": {
					"status": {
						"type": "string",
						"enum": [
							"stored"
						]
					},
					"provisionedAt": {
						"type": "string",
						"description": "ISO timestamp of initial provisioning"
					}
				},
				"required": [
					"status",
					"provisionedAt"
				]
			},
			"FixCredentialsNone": {
				"type": "object",
				"properties": {
					"status": {
						"type": "string",
						"enum": [
							"none"
						]
					}
				},
				"required": [
					"status"
				]
			},
			"FixCredentialsProvisionResponse": {
				"type": "object",
				"properties": {
					"status": {
						"type": "string",
						"enum": [
							"provisioned"
						]
					},
					"provisionedAt": {
						"type": "string",
						"description": "ISO timestamp of provisioning"
					}
				},
				"required": [
					"status",
					"provisionedAt"
				]
			},
			"FixCredentialsProvisionRequest": {
				"type": "object",
				"properties": {
					"serverId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"traderId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					},
					"password": {
						"type": "string",
						"pattern": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^a-zA-Z\\d\\s])[^\\s]{8,16}$",
						"description": "Optional caller-supplied investor password (plaintext). Omit to have one generated. Must be 8–16 chars with at least one lowercase, uppercase, digit, and symbol, and no whitespace."
					}
				},
				"required": [
					"serverId",
					"traderId",
					"env"
				]
			},
			"FixCredentialsStageProvisionRequest": {
				"type": "object",
				"properties": {
					"accountId": {
						"type": "string",
						"minLength": 1,
						"description": "The opaque accountId the account list on this stage returned for the account"
					},
					"password": {
						"type": "string",
						"pattern": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^a-zA-Z\\d\\s])[^\\s]{8,16}$",
						"secret": true,
						"description": "Optional caller-supplied investor password (plaintext). Omit to have one generated. Must be 8–16 chars with at least one lowercase, uppercase, digit, and symbol, and no whitespace."
					}
				},
				"required": [
					"accountId"
				],
				"additionalProperties": false
			},
			"GetAccountsByTraderEmailResponse": {
				"type": "object",
				"properties": {
					"accounts": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/TradingAccount"
						}
					}
				},
				"required": [
					"accounts"
				]
			},
			"TradingAccount": {
				"type": "object",
				"properties": {
					"brand": {
						"type": "string",
						"enum": [
							"axiory",
							"purpleTrading",
							"fintokei"
						]
					},
					"accountNumber": {
						"type": "string"
					},
					"traderId": {
						"type": "number"
					},
					"email": {
						"type": "string"
					},
					"platform": {
						"type": "string",
						"enum": [
							"mt4",
							"mt5",
							"ctrader",
							"yourbourse"
						]
					},
					"balance": {
						"type": "number"
					},
					"leverage": {
						"type": "number"
					},
					"group": {
						"type": "string"
					},
					"serverId": {
						"type": "number"
					},
					"serverName": {
						"type": "string"
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					},
					"hasOpenPositions": {
						"type": "boolean"
					},
					"currency": {
						"type": "string",
						"enum": [
							"AED",
							"AFN",
							"ALL",
							"AMD",
							"ANG",
							"AOA",
							"ARS",
							"AUD",
							"AWG",
							"AZN",
							"BAM",
							"BBD",
							"BDT",
							"BGN",
							"BHD",
							"BIF",
							"BMD",
							"BND",
							"BOB",
							"BRL",
							"BSD",
							"BTC",
							"BTN",
							"BWP",
							"BYN",
							"BZD",
							"CAD",
							"CDF",
							"CHF",
							"CLF",
							"CLP",
							"CNH",
							"CNY",
							"COP",
							"CRC",
							"CUC",
							"CUP",
							"CVE",
							"CZK",
							"DJF",
							"DKK",
							"DOP",
							"DZD",
							"EGP",
							"ERN",
							"ETB",
							"EUR",
							"FJD",
							"FKP",
							"GBP",
							"GEL",
							"GGP",
							"GHS",
							"GIP",
							"GMD",
							"GNF",
							"GTQ",
							"GYD",
							"HKD",
							"HNL",
							"HRK",
							"HTG",
							"HUF",
							"IDR",
							"ILS",
							"IMP",
							"INR",
							"IQD",
							"IRR",
							"ISK",
							"JEP",
							"JMD",
							"JOD",
							"JPY",
							"KES",
							"KGS",
							"KHR",
							"KMF",
							"KPW",
							"KRW",
							"KWD",
							"KYD",
							"KZT",
							"LAK",
							"LBP",
							"LKR",
							"LRD",
							"LSL",
							"LYD",
							"MAD",
							"MDL",
							"MGA",
							"MKD",
							"MMK",
							"MNT",
							"MOP",
							"MRO",
							"MRU",
							"MUR",
							"MVR",
							"MWK",
							"MXN",
							"MYR",
							"MZN",
							"NAD",
							"NGN",
							"NIO",
							"NOK",
							"NPR",
							"NZD",
							"OMR",
							"PAB",
							"PEN",
							"PGK",
							"PHP",
							"PKR",
							"PLN",
							"PYG",
							"QAR",
							"RON",
							"RSD",
							"RUB",
							"RWF",
							"SAR",
							"SBD",
							"SCR",
							"SDG",
							"SEK",
							"SGD",
							"SHP",
							"SLL",
							"SOS",
							"SRD",
							"SSP",
							"STD",
							"STN",
							"SVC",
							"SYP",
							"SZL",
							"THB",
							"TJS",
							"TMT",
							"TND",
							"TOP",
							"TRY",
							"TTD",
							"TWD",
							"TZS",
							"UAH",
							"UGX",
							"USD",
							"UYU",
							"UZS",
							"VEF",
							"VES",
							"VND",
							"VUV",
							"WST",
							"XAF",
							"XAG",
							"XAU",
							"XCD",
							"XDR",
							"XOF",
							"XPD",
							"XPF",
							"XPT",
							"YER",
							"ZAR",
							"ZMW",
							"ZWL"
						]
					},
					"accountType": {
						"type": "string",
						"nullable": true,
						"enum": [
							"ALPHA",
							"MAX",
							"MAXISL",
							"NANO",
							"NANOISL",
							"STANDARD",
							"STANDARDISL",
							"TAKUMIS",
							"TERA",
							"TERAISL",
							"WALLET",
							"INVESTOR",
							"ZERO",
							"ZEROISL",
							null
						]
					}
				},
				"required": [
					"brand",
					"accountNumber",
					"traderId",
					"email",
					"platform",
					"balance",
					"leverage",
					"group",
					"serverId",
					"serverName",
					"env",
					"hasOpenPositions",
					"currency",
					"accountType"
				]
			},
			"GetStageAccountsResponse": {
				"type": "object",
				"properties": {
					"accounts": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/StageTradingAccount"
						}
					}
				},
				"required": [
					"accounts"
				]
			},
			"StageTradingAccount": {
				"type": "object",
				"properties": {
					"brand": {
						"type": "string",
						"enum": [
							"axiory",
							"purpleTrading",
							"fintokei"
						]
					},
					"accountNumber": {
						"type": "string"
					},
					"traderId": {
						"type": "number"
					},
					"email": {
						"type": "string"
					},
					"platform": {
						"type": "string",
						"enum": [
							"mt4",
							"mt5",
							"ctrader",
							"yourbourse"
						]
					},
					"balance": {
						"type": "number"
					},
					"leverage": {
						"type": "number"
					},
					"group": {
						"type": "string"
					},
					"serverId": {
						"type": "number"
					},
					"serverName": {
						"type": "string"
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					},
					"hasOpenPositions": {
						"type": "boolean"
					},
					"currency": {
						"type": "string",
						"enum": [
							"AED",
							"AFN",
							"ALL",
							"AMD",
							"ANG",
							"AOA",
							"ARS",
							"AUD",
							"AWG",
							"AZN",
							"BAM",
							"BBD",
							"BDT",
							"BGN",
							"BHD",
							"BIF",
							"BMD",
							"BND",
							"BOB",
							"BRL",
							"BSD",
							"BTC",
							"BTN",
							"BWP",
							"BYN",
							"BZD",
							"CAD",
							"CDF",
							"CHF",
							"CLF",
							"CLP",
							"CNH",
							"CNY",
							"COP",
							"CRC",
							"CUC",
							"CUP",
							"CVE",
							"CZK",
							"DJF",
							"DKK",
							"DOP",
							"DZD",
							"EGP",
							"ERN",
							"ETB",
							"EUR",
							"FJD",
							"FKP",
							"GBP",
							"GEL",
							"GGP",
							"GHS",
							"GIP",
							"GMD",
							"GNF",
							"GTQ",
							"GYD",
							"HKD",
							"HNL",
							"HRK",
							"HTG",
							"HUF",
							"IDR",
							"ILS",
							"IMP",
							"INR",
							"IQD",
							"IRR",
							"ISK",
							"JEP",
							"JMD",
							"JOD",
							"JPY",
							"KES",
							"KGS",
							"KHR",
							"KMF",
							"KPW",
							"KRW",
							"KWD",
							"KYD",
							"KZT",
							"LAK",
							"LBP",
							"LKR",
							"LRD",
							"LSL",
							"LYD",
							"MAD",
							"MDL",
							"MGA",
							"MKD",
							"MMK",
							"MNT",
							"MOP",
							"MRO",
							"MRU",
							"MUR",
							"MVR",
							"MWK",
							"MXN",
							"MYR",
							"MZN",
							"NAD",
							"NGN",
							"NIO",
							"NOK",
							"NPR",
							"NZD",
							"OMR",
							"PAB",
							"PEN",
							"PGK",
							"PHP",
							"PKR",
							"PLN",
							"PYG",
							"QAR",
							"RON",
							"RSD",
							"RUB",
							"RWF",
							"SAR",
							"SBD",
							"SCR",
							"SDG",
							"SEK",
							"SGD",
							"SHP",
							"SLL",
							"SOS",
							"SRD",
							"SSP",
							"STD",
							"STN",
							"SVC",
							"SYP",
							"SZL",
							"THB",
							"TJS",
							"TMT",
							"TND",
							"TOP",
							"TRY",
							"TTD",
							"TWD",
							"TZS",
							"UAH",
							"UGX",
							"USD",
							"UYU",
							"UZS",
							"VEF",
							"VES",
							"VND",
							"VUV",
							"WST",
							"XAF",
							"XAG",
							"XAU",
							"XCD",
							"XDR",
							"XOF",
							"XPD",
							"XPF",
							"XPT",
							"YER",
							"ZAR",
							"ZMW",
							"ZWL"
						]
					},
					"accountType": {
						"type": "string",
						"nullable": true,
						"enum": [
							"ALPHA",
							"MAX",
							"MAXISL",
							"NANO",
							"NANOISL",
							"STANDARD",
							"STANDARDISL",
							"TAKUMIS",
							"TERA",
							"TERAISL",
							"WALLET",
							"INVESTOR",
							"ZERO",
							"ZEROISL",
							null
						]
					},
					"accountId": {
						"type": "string",
						"description": "Opaque identifier of the account on this stage. Deterministic per account, bound to the brand and the stage, and the only way the other routes of this stage address it."
					}
				},
				"required": [
					"brand",
					"accountNumber",
					"traderId",
					"email",
					"platform",
					"balance",
					"leverage",
					"group",
					"serverId",
					"serverName",
					"env",
					"hasOpenPositions",
					"currency",
					"accountType",
					"accountId"
				]
			},
			"TradesPage": {
				"type": "object",
				"properties": {
					"items": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/Trade"
						}
					},
					"nextCursor": {
						"type": "string",
						"nullable": true
					},
					"hasMore": {
						"type": "boolean"
					}
				},
				"required": [
					"items",
					"nextCursor",
					"hasMore"
				]
			},
			"Trade": {
				"type": "object",
				"properties": {
					"brand": {
						"type": "string",
						"enum": [
							"axiory",
							"purpleTrading",
							"fintokei"
						]
					},
					"positionId": {
						"type": "number"
					},
					"openedAt": {
						"type": "string"
					},
					"closedAt": {
						"type": "string"
					},
					"side": {
						"type": "string",
						"enum": [
							"LONG",
							"SHORT"
						]
					},
					"volume": {
						"type": "number"
					},
					"lot": {
						"type": "number"
					},
					"symbolId": {
						"type": "string"
					},
					"stopLoss": {
						"type": "number"
					},
					"takeProfit": {
						"type": "number"
					},
					"openPrice": {
						"type": "number"
					},
					"closePrice": {
						"type": "number"
					},
					"swap": {
						"type": "number"
					},
					"commission": {
						"type": "number"
					},
					"profit": {
						"type": "number"
					},
					"onCredit": {
						"type": "boolean"
					},
					"status": {
						"type": "string",
						"enum": [
							"OPEN",
							"CLOSED",
							"ALL"
						]
					}
				},
				"required": [
					"brand",
					"positionId",
					"openedAt",
					"side",
					"symbolId",
					"onCredit",
					"status"
				]
			},
			"TransactionsPage": {
				"type": "object",
				"properties": {
					"items": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/Transaction"
						}
					},
					"nextCursor": {
						"type": "string",
						"nullable": true
					},
					"hasMore": {
						"type": "boolean"
					}
				},
				"required": [
					"items",
					"nextCursor",
					"hasMore"
				]
			},
			"Transaction": {
				"type": "object",
				"properties": {
					"transactionId": {
						"type": "number"
					},
					"createdAt": {
						"type": "string"
					},
					"transactionType": {
						"type": "string",
						"enum": [
							"deposit",
							"withdrawal",
							"credit",
							"other"
						]
					},
					"comment": {
						"type": "string",
						"nullable": true
					},
					"amount": {
						"type": "number"
					},
					"feeDeducted": {
						"type": "boolean"
					}
				},
				"required": [
					"transactionId",
					"createdAt",
					"transactionType",
					"comment",
					"amount",
					"feeDeducted"
				]
			},
			"AccountProvisioningAcceptedResponse": {
				"type": "object",
				"properties": {
					"requestId": {
						"type": "string"
					}
				},
				"required": [
					"requestId"
				]
			},
			"CreateLiveAccountRequest": {
				"type": "object",
				"properties": {
					"ctrader": {
						"$ref": "#/components/schemas/CtraderRequestOptions"
					},
					"correlationId": {
						"type": "string",
						"minLength": 1,
						"description": "Caller's correlation id, echoed back verbatim inside the terminal callback payload."
					},
					"callbackUrl": {
						"type": "string",
						"format": "uri",
						"description": "Callback delivery URL. Consumed and stripped by the engine async proxy before the request reaches this service — axi-services never reads this field itself; documented here only because the published contract mirrors the wire contract."
					},
					"platform": {
						"type": "string",
						"enum": [
							"CTRADER"
						],
						"description": "Target trading platform. Pinned to `CTRADER` for this contract version — the bridge only opens cTrader accounts today. Platform-specific fields are never flat on the body; they live under the key matching the lowercased platform value (`ctrader`)."
					},
					"accountType": {
						"type": "string",
						"minLength": 1,
						"description": "Strategy Builder fintech account type. Server-side grouping is driven by this value; the specific enum is pending product/FinTech input."
					},
					"alwaysMaxLeverage": {
						"type": "boolean",
						"description": "Whether the account always trades at max leverage. Required — a request omitting this field is rejected at the gateway with a 400 naming the field."
					},
					"maxLeverage": {
						"type": "string",
						"minLength": 1,
						"description": "Opaque leverage-tier identifier (my-axiory's Leverage enum, e.g. 'Leverage100'). Optional."
					},
					"currency": {
						"type": "string",
						"minLength": 1,
						"description": "Account currency code."
					}
				},
				"required": [
					"ctrader",
					"correlationId",
					"callbackUrl",
					"platform",
					"accountType",
					"alwaysMaxLeverage",
					"currency"
				]
			},
			"CtraderRequestOptions": {
				"type": "object",
				"properties": {
					"ctid": {
						"type": "string",
						"format": "email",
						"description": "Corporate cTrader ID alias email (app-held credentials pool). Substitutes the fintech-api account-creation email to drive cTID attach; my-axiory rewrites it to the end-user's email in-SFN before completion."
					}
				},
				"required": [
					"ctid"
				],
				"description": "cTrader-specific request options. Required whenever `platform` is `CTRADER`, and forbidden for any other platform — a rule enforced by this service (see `backend/shared/validation.ts`), because OpenAPI 3.0 cannot express conditional requiredness."
			},
			"CreateDemoAccountRequest": {
				"type": "object",
				"properties": {
					"ctrader": {
						"$ref": "#/components/schemas/CtraderDemoRequestOptions"
					},
					"correlationId": {
						"type": "string",
						"minLength": 1,
						"description": "Caller's correlation id, echoed back verbatim inside the terminal callback payload."
					},
					"callbackUrl": {
						"type": "string",
						"format": "uri",
						"description": "Callback delivery URL. Consumed and stripped by the engine async proxy before the request reaches this service — axi-services never reads this field itself; documented here only because the published contract mirrors the wire contract."
					},
					"platform": {
						"$ref": "#/components/schemas/DemoAccountPlatform"
					},
					"deposit": {
						"type": "number",
						"description": "Initial demo deposit amount. Range validation happens later, in-SFN — this layer only requires the field to be a number."
					},
					"leverage": {
						"type": "string",
						"minLength": 1,
						"description": "Opaque leverage-tier identifier (my-axiory's Leverage enum, e.g. 'Leverage100'). Required for demo accounts — DemoAccountOpeningSMInput.data.leverage is a required field and account opening throws without it."
					},
					"currency": {
						"type": "string",
						"minLength": 1,
						"description": "Account currency code."
					}
				},
				"required": [
					"correlationId",
					"callbackUrl",
					"platform",
					"deposit",
					"leverage",
					"currency"
				]
			},
			"CtraderDemoRequestOptions": {
				"type": "object",
				"properties": {
					"ctid": {
						"type": "string",
						"format": "email",
						"description": "Corporate cTrader ID alias email (app-held credentials pool). Substitutes the fintech-api account-creation email to drive cTID attach; my-axiory rewrites it to the end-user's email in-SFN before completion."
					},
					"accountType": {
						"type": "string",
						"minLength": 1,
						"description": "Strategy Builder fintech account type. Server-side grouping is driven by this value; the specific enum is pending product/FinTech input."
					},
					"alwaysMaxLeverage": {
						"type": "boolean",
						"description": "Whether the account always trades at max leverage. Required inside this block — a `CTRADER` request whose block omits it is rejected at the gateway with a 400 naming the field."
					}
				},
				"required": [
					"ctid",
					"accountType",
					"alwaysMaxLeverage"
				],
				"description": "cTrader-specific demo request options. Required whenever the demo `platform` is `CTRADER`, and forbidden for any other platform — a rule enforced by this service (see `backend/shared/validation.ts`), because OpenAPI 3.0 cannot express conditional requiredness."
			},
			"AccountProvisioningStatusResponse": {
				"type": "object",
				"properties": {
					"requestId": {
						"type": "string"
					},
					"status": {
						"$ref": "#/components/schemas/AccountProvisioningStatusState"
					},
					"platform": {
						"$ref": "#/components/schemas/DemoAccountPlatform"
					},
					"result": {
						"$ref": "#/components/schemas/AccountProvisioningStatusResult"
					},
					"updatedAt": {
						"type": "string",
						"description": "ISO timestamp of the last status transition."
					}
				},
				"required": [
					"requestId",
					"status",
					"updatedAt"
				]
			},
			"CreateDemoAccountRequestBody": {
				"type": "object",
				"properties": {
					"platform": {
						"$ref": "#/components/schemas/DemoAccountRequestPlatform"
					},
					"ctrader": {
						"$ref": "#/components/schemas/DemoAccountRequestCtraderOptions"
					},
					"correlationId": {
						"type": "string",
						"minLength": 1,
						"description": "Caller's correlation id, echoed back verbatim inside the terminal callback payload."
					},
					"callbackUrl": {
						"type": "string",
						"format": "uri",
						"description": "Callback delivery URL. Required of a first-party app and refused for a self-service app by the engine async proxy, which consumes and strips it before the request reaches this service."
					},
					"deposit": {
						"type": "number",
						"description": "Initial demo deposit amount. Range validation happens later, in-SFN."
					},
					"leverage": {
						"$ref": "#/components/schemas/AccountRequestLeverage"
					},
					"currency": {
						"$ref": "#/components/schemas/AccountRequestCurrency"
					}
				},
				"required": [
					"platform",
					"correlationId",
					"deposit",
					"leverage",
					"currency"
				],
				"additionalProperties": false
			},
			"DemoAccountRequestPlatform": {
				"type": "string",
				"enum": [
					"ctrader",
					"yourbourse"
				],
				"description": "Target trading platform, spelled as the account list spells it. `ctrader` bridges to my-axiory and requires the `ctrader` options block; `yourbourse` calls the YourBourse Admin API directly and carries no options block."
			},
			"DemoAccountRequestCtraderOptions": {
				"type": "object",
				"properties": {
					"ctid": {
						"type": "string",
						"format": "email",
						"description": "Corporate cTrader ID alias email (app-held credentials pool). Substitutes the fintech-api account-creation email to drive cTID attach; my-axiory rewrites it to the end-user's email in-SFN before completion."
					},
					"accountType": {
						"$ref": "#/components/schemas/AccountRequestAccountType"
					},
					"alwaysMaxLeverage": {
						"type": "boolean",
						"description": "Whether the account always trades at max leverage."
					}
				},
				"required": [
					"ctid",
					"accountType",
					"alwaysMaxLeverage"
				],
				"additionalProperties": false,
				"description": "cTrader-specific demo request options. Required whenever `platform` is `ctrader`, and refused for any other platform — enforced by this service, because OpenAPI 3.0 cannot express conditional requiredness.",
				"requiredWhen": {
					"platform": "ctrader"
				}
			},
			"AccountRequestAccountType": {
				"type": "string",
				"enum": [
					"NANO",
					"STANDARD",
					"MAX",
					"ZERO",
					"NANOISL",
					"STANDARDISL",
					"MAXISL",
					"ZEROISL",
					"WALLET",
					"TAKUMIS"
				],
				"description": "Strategy Builder fintech account type, spelled as the account list spells it."
			},
			"AccountRequestLeverage": {
				"anyOf": [
					{
						"type": "number",
						"enum": [
							1
						]
					},
					{
						"type": "number",
						"enum": [
							10
						]
					},
					{
						"type": "number",
						"enum": [
							25
						]
					},
					{
						"type": "number",
						"enum": [
							50
						]
					},
					{
						"type": "number",
						"enum": [
							100
						]
					},
					{
						"type": "number",
						"enum": [
							200
						]
					},
					{
						"type": "number",
						"enum": [
							300
						]
					},
					{
						"type": "number",
						"enum": [
							400
						]
					},
					{
						"type": "number",
						"enum": [
							500
						]
					},
					{
						"type": "number",
						"enum": [
							600
						]
					},
					{
						"type": "number",
						"enum": [
							777
						]
					},
					{
						"type": "number",
						"enum": [
							800
						]
					},
					{
						"type": "number",
						"enum": [
							1000
						]
					},
					{
						"type": "number",
						"enum": [
							2000
						]
					}
				],
				"description": "Leverage ratio, as the number after `1:`. Mapped to my-axiory leverage tiers inside this service."
			},
			"AccountRequestCurrency": {
				"type": "string",
				"enum": [
					"AED",
					"AFN",
					"ALL",
					"AMD",
					"ANG",
					"AOA",
					"ARS",
					"AUD",
					"AWG",
					"AZN",
					"BAM",
					"BBD",
					"BDT",
					"BGN",
					"BHD",
					"BIF",
					"BMD",
					"BND",
					"BOB",
					"BRL",
					"BSD",
					"BTC",
					"BTN",
					"BWP",
					"BYN",
					"BZD",
					"CAD",
					"CDF",
					"CHF",
					"CLF",
					"CLP",
					"CNH",
					"CNY",
					"COP",
					"CRC",
					"CUC",
					"CUP",
					"CVE",
					"CZK",
					"DJF",
					"DKK",
					"DOP",
					"DZD",
					"EGP",
					"ERN",
					"ETB",
					"EUR",
					"FJD",
					"FKP",
					"GBP",
					"GEL",
					"GGP",
					"GHS",
					"GIP",
					"GMD",
					"GNF",
					"GTQ",
					"GYD",
					"HKD",
					"HNL",
					"HRK",
					"HTG",
					"HUF",
					"IDR",
					"ILS",
					"IMP",
					"INR",
					"IQD",
					"IRR",
					"ISK",
					"JEP",
					"JMD",
					"JOD",
					"JPY",
					"KES",
					"KGS",
					"KHR",
					"KMF",
					"KPW",
					"KRW",
					"KWD",
					"KYD",
					"KZT",
					"LAK",
					"LBP",
					"LKR",
					"LRD",
					"LSL",
					"LYD",
					"MAD",
					"MDL",
					"MGA",
					"MKD",
					"MMK",
					"MNT",
					"MOP",
					"MRO",
					"MRU",
					"MUR",
					"MVR",
					"MWK",
					"MXN",
					"MYR",
					"MZN",
					"NAD",
					"NGN",
					"NIO",
					"NOK",
					"NPR",
					"NZD",
					"OMR",
					"PAB",
					"PEN",
					"PGK",
					"PHP",
					"PKR",
					"PLN",
					"PYG",
					"QAR",
					"RON",
					"RSD",
					"RUB",
					"RWF",
					"SAR",
					"SBD",
					"SCR",
					"SDG",
					"SEK",
					"SGD",
					"SHP",
					"SLL",
					"SOS",
					"SRD",
					"SSP",
					"STD",
					"STN",
					"SVC",
					"SYP",
					"SZL",
					"THB",
					"TJS",
					"TMT",
					"TND",
					"TOP",
					"TRY",
					"TTD",
					"TWD",
					"TZS",
					"UAH",
					"UGX",
					"USD",
					"UYU",
					"UZS",
					"VEF",
					"VES",
					"VND",
					"VUV",
					"WST",
					"XAF",
					"XAG",
					"XAU",
					"XCD",
					"XDR",
					"XOF",
					"XPD",
					"XPF",
					"XPT",
					"YER",
					"ZAR",
					"ZMW",
					"ZWL"
				],
				"description": "Account currency, one of the currency codes the report server records."
			},
			"CreateLiveAccountRequestBody": {
				"type": "object",
				"properties": {
					"platform": {
						"$ref": "#/components/schemas/LiveAccountRequestPlatform"
					},
					"ctrader": {
						"$ref": "#/components/schemas/LiveAccountRequestCtraderOptions"
					},
					"correlationId": {
						"type": "string",
						"minLength": 1,
						"description": "Caller's correlation id, echoed back verbatim inside the terminal callback payload."
					},
					"callbackUrl": {
						"type": "string",
						"format": "uri",
						"description": "Callback delivery URL. Required of a first-party app and refused for a self-service app by the engine async proxy, which consumes and strips it before the request reaches this service."
					},
					"accountType": {
						"$ref": "#/components/schemas/AccountRequestAccountType"
					},
					"alwaysMaxLeverage": {
						"type": "boolean",
						"description": "Whether the account always trades at max leverage."
					},
					"maxLeverage": {
						"$ref": "#/components/schemas/AccountRequestLeverage"
					},
					"currency": {
						"$ref": "#/components/schemas/AccountRequestCurrency"
					}
				},
				"required": [
					"platform",
					"ctrader",
					"correlationId",
					"accountType",
					"alwaysMaxLeverage",
					"currency"
				],
				"additionalProperties": false
			},
			"LiveAccountRequestPlatform": {
				"type": "string",
				"enum": [
					"ctrader"
				],
				"description": "Target trading platform, spelled as the account list spells it. Live accounts open on cTrader only; platform-specific fields live under the `ctrader` key."
			},
			"LiveAccountRequestCtraderOptions": {
				"type": "object",
				"properties": {
					"ctid": {
						"type": "string",
						"format": "email",
						"description": "Corporate cTrader ID alias email (app-held credentials pool). Substitutes the fintech-api account-creation email to drive cTID attach; my-axiory rewrites it to the end-user's email in-SFN before completion."
					}
				},
				"required": [
					"ctid"
				],
				"additionalProperties": false,
				"description": "cTrader-specific live request options."
			},
			"TradingPositionsResponse": {
				"type": "object",
				"properties": {
					"positions": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/Position"
						}
					},
					"asOf": {
						"type": "string"
					}
				},
				"required": [
					"positions",
					"asOf"
				]
			},
			"Position": {
				"type": "object",
				"properties": {
					"positionId": {
						"type": "string"
					},
					"symbol": {
						"type": "string"
					},
					"side": {
						"$ref": "#/components/schemas/OrderSide"
					},
					"volume": {
						"type": "number"
					},
					"entryPrice": {
						"type": "number"
					},
					"currentPrice": {
						"type": "number",
						"nullable": true
					},
					"unrealisedPnl": {
						"$ref": "#/components/schemas/Money"
					},
					"swap": {
						"type": "number",
						"nullable": true
					},
					"commission": {
						"type": "number",
						"nullable": true
					},
					"stopLoss": {
						"type": "number",
						"nullable": true
					},
					"takeProfit": {
						"type": "number",
						"nullable": true
					},
					"openedAt": {
						"type": "string"
					},
					"linkedOrderIds": {
						"type": "array",
						"items": {
							"type": "string"
						}
					},
					"divergence": {
						"$ref": "#/components/schemas/PositionDivergence"
					},
					"divergenceNote": {
						"type": "string",
						"nullable": true
					},
					"confirmedAt": {
						"type": "string"
					}
				},
				"required": [
					"positionId",
					"symbol",
					"side",
					"volume",
					"entryPrice",
					"currentPrice",
					"unrealisedPnl",
					"swap",
					"commission",
					"stopLoss",
					"takeProfit",
					"openedAt",
					"linkedOrderIds",
					"divergence",
					"divergenceNote",
					"confirmedAt"
				]
			},
			"OrderSide": {
				"type": "string",
				"enum": [
					"BUY",
					"SELL"
				]
			},
			"Money": {
				"type": "object",
				"properties": {
					"amount": {
						"type": "number"
					},
					"currency": {
						"type": "string"
					},
					"converted": {
						"type": "object",
						"nullable": true,
						"properties": {
							"amount": {
								"type": "number"
							},
							"currency": {
								"type": "string",
								"enum": [
									"USD"
								]
							},
							"rate": {
								"type": "number"
							},
							"rateSource": {
								"type": "string"
							}
						},
						"required": [
							"amount",
							"currency",
							"rate",
							"rateSource"
						]
					}
				},
				"required": [
					"amount",
					"currency",
					"converted"
				]
			},
			"PositionDivergence": {
				"type": "string",
				"enum": [
					"new",
					"matched",
					"diverged"
				]
			},
			"TradingExecutionError": {
				"type": "object",
				"properties": {
					"code": {
						"$ref": "#/components/schemas/TradingExecutionErrorCode"
					},
					"message": {
						"type": "string"
					},
					"details": {
						"$ref": "#/components/schemas/TradingExecutionErrorDetails"
					}
				},
				"required": [
					"code",
					"message"
				]
			},
			"TradingExecutionErrorCode": {
				"type": "string",
				"enum": [
					"validation_error",
					"idempotency_key_required",
					"account_not_owned",
					"scope_insufficient",
					"env_not_permitted",
					"operator_only",
					"platform_not_supported",
					"order_not_found",
					"position_not_found",
					"session_not_found",
					"session_connecting",
					"session_reconciling",
					"session_reconnecting",
					"session_owned_elsewhere",
					"session_login_conflict",
					"idempotency_key_reused",
					"lock_timeout",
					"risk_check_failed",
					"kill_switch_active",
					"broker_rejected",
					"rate_limited",
					"broker_unavailable",
					"idempotency_store_unavailable",
					"account_not_found",
					"restriction_not_applicable",
					"restriction_value_unresolvable",
					"assumed_default_mismatch",
					"account_id_unavailable",
					"account_unavailable"
				]
			},
			"TradingExecutionErrorDetails": {
				"type": "object",
				"properties": {
					"field": {
						"type": "string"
					},
					"retryAfterMs": {
						"type": "integer",
						"minimum": 0
					},
					"check": {
						"$ref": "#/components/schemas/RiskCheckName"
					},
					"limit": {
						"type": "number"
					},
					"actual": {
						"type": "number"
					},
					"reason": {
						"type": "string",
						"enum": [
							"daily_loss",
							"circuit_breaker"
						]
					},
					"resetsAt": {
						"type": "string"
					},
					"brokerReason": {
						"type": "string"
					},
					"action": {
						"type": "string",
						"enum": [
							"retry",
							"disconnect_other_client",
							"contact_support"
						]
					}
				}
			},
			"RiskCheckName": {
				"type": "string",
				"enum": [
					"kill_switch",
					"rate_limit",
					"symbol_whitelist",
					"position_size",
					"open_positions",
					"daily_loss",
					"volume_validation"
				]
			},
			"TradingOrdersResponse": {
				"type": "object",
				"properties": {
					"orders": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/Order"
						}
					},
					"complete": {
						"type": "boolean"
					},
					"asOf": {
						"type": "string"
					}
				},
				"required": [
					"orders",
					"complete",
					"asOf"
				]
			},
			"Order": {
				"type": "object",
				"properties": {
					"orderId": {
						"type": "string"
					},
					"clOrdId": {
						"type": "string"
					},
					"symbol": {
						"type": "string"
					},
					"side": {
						"$ref": "#/components/schemas/OrderSide"
					},
					"type": {
						"$ref": "#/components/schemas/OrderType"
					},
					"timeInForce": {
						"$ref": "#/components/schemas/TimeInForce"
					},
					"volume": {
						"type": "number"
					},
					"filledVolume": {
						"type": "number"
					},
					"price": {
						"type": "number",
						"nullable": true
					},
					"stopPrice": {
						"type": "number",
						"nullable": true
					},
					"positionId": {
						"type": "string",
						"nullable": true
					},
					"status": {
						"$ref": "#/components/schemas/OrderStatus"
					},
					"placedBy": {
						"type": "string",
						"nullable": true
					},
					"createdAt": {
						"type": "string"
					},
					"updatedAt": {
						"type": "string"
					},
					"expireTime": {
						"type": "string",
						"nullable": true
					},
					"confirmedAt": {
						"type": "string"
					}
				},
				"required": [
					"orderId",
					"clOrdId",
					"symbol",
					"side",
					"type",
					"timeInForce",
					"volume",
					"filledVolume",
					"price",
					"stopPrice",
					"positionId",
					"status",
					"placedBy",
					"createdAt",
					"updatedAt",
					"expireTime",
					"confirmedAt"
				]
			},
			"OrderType": {
				"type": "string",
				"enum": [
					"MARKET",
					"LIMIT",
					"STOP"
				]
			},
			"TimeInForce": {
				"type": "string",
				"enum": [
					"GTC",
					"DAY",
					"IOC",
					"FOK",
					"GTD"
				]
			},
			"OrderStatus": {
				"type": "string",
				"enum": [
					"pending",
					"partiallyFilled",
					"filled",
					"cancelled",
					"rejected",
					"expired"
				]
			},
			"TradingQuoteResponse": {
				"type": "object",
				"properties": {
					"symbol": {
						"type": "string"
					},
					"bid": {
						"type": "number"
					},
					"ask": {
						"type": "number"
					},
					"spread": {
						"type": "number"
					},
					"confirmedAt": {
						"type": "string"
					},
					"stale": {
						"type": "boolean"
					}
				},
				"required": [
					"symbol",
					"bid",
					"ask",
					"spread",
					"confirmedAt",
					"stale"
				]
			},
			"TradingQuotesResponse": {
				"type": "object",
				"properties": {
					"quotes": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/Quote"
						}
					},
					"missing": {
						"type": "array",
						"items": {
							"type": "string"
						}
					}
				},
				"required": [
					"quotes",
					"missing"
				]
			},
			"Quote": {
				"type": "object",
				"properties": {
					"symbol": {
						"type": "string"
					},
					"bid": {
						"type": "number"
					},
					"ask": {
						"type": "number"
					},
					"spread": {
						"type": "number"
					},
					"confirmedAt": {
						"type": "string"
					},
					"stale": {
						"type": "boolean"
					}
				},
				"required": [
					"symbol",
					"bid",
					"ask",
					"spread",
					"confirmedAt",
					"stale"
				]
			},
			"TradingSymbolsResponse": {
				"type": "object",
				"properties": {
					"symbols": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/TradingSymbol"
						}
					}
				},
				"required": [
					"symbols"
				]
			},
			"TradingSymbol": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string"
					},
					"id": {
						"type": "integer"
					},
					"description": {
						"type": "string",
						"nullable": true
					},
					"assetClass": {
						"type": "string",
						"nullable": true
					},
					"assetClassGroup": {
						"type": "string",
						"nullable": true,
						"enum": [
							"fx",
							"indices",
							"commodities",
							"other",
							null
						]
					},
					"lotSize": {
						"type": "number"
					},
					"minVolume": {
						"type": "number"
					},
					"maxVolume": {
						"type": "number",
						"nullable": true
					},
					"volumeStep": {
						"type": "number"
					},
					"digits": {
						"type": "integer",
						"nullable": true
					},
					"quoteCurrency": {
						"type": "string",
						"nullable": true
					}
				},
				"required": [
					"name",
					"id",
					"description",
					"assetClass",
					"assetClassGroup",
					"lotSize",
					"minVolume",
					"maxVolume",
					"volumeStep",
					"digits",
					"quoteCurrency"
				]
			},
			"TradingSessionStatusResponse": {
				"type": "object",
				"properties": {
					"trade": {
						"$ref": "#/components/schemas/SessionConnection"
					},
					"quote": {
						"$ref": "#/components/schemas/SessionConnection"
					},
					"tradingReady": {
						"type": "boolean"
					},
					"reconciliationComplete": {
						"type": "boolean"
					},
					"orderReconciliation": {
						"type": "string",
						"enum": [
							"complete",
							"timeout",
							"pending"
						]
					},
					"positionSnapshotDefinitive": {
						"type": "boolean"
					},
					"subscribedSymbols": {
						"type": "array",
						"items": {
							"type": "string"
						}
					},
					"subscribedSymbolCap": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"idleSince": {
						"type": "string",
						"nullable": true
					},
					"risk": {
						"type": "object",
						"properties": {
							"killSwitch": {
								"type": "object",
								"properties": {
									"active": {
										"type": "boolean"
									},
									"reason": {
										"type": "string",
										"nullable": true,
										"enum": [
											"daily_loss",
											"circuit_breaker",
											null
										]
									},
									"resetsAt": {
										"type": "string",
										"nullable": true
									}
								},
								"required": [
									"active",
									"reason",
									"resetsAt"
								]
							},
							"dailyPnl": {
								"$ref": "#/components/schemas/Money"
							}
						},
						"required": [
							"killSwitch",
							"dailyPnl"
						]
					},
					"asOf": {
						"type": "string"
					}
				},
				"required": [
					"trade",
					"quote",
					"tradingReady",
					"reconciliationComplete",
					"orderReconciliation",
					"positionSnapshotDefinitive",
					"subscribedSymbols",
					"subscribedSymbolCap",
					"idleSince",
					"risk",
					"asOf"
				]
			},
			"SessionConnection": {
				"type": "object",
				"properties": {
					"state": {
						"$ref": "#/components/schemas/SessionState"
					},
					"reason": {
						"type": "string",
						"nullable": true,
						"enum": [
							"login_taken_by_external_client",
							"broker_unreachable",
							"converging",
							null
						]
					},
					"connectedAt": {
						"type": "string",
						"nullable": true
					},
					"lastHeartbeatAt": {
						"type": "string",
						"nullable": true
					},
					"reconnectAttempts": {
						"type": "integer",
						"minimum": 0
					},
					"nextRetryAt": {
						"type": "string",
						"nullable": true
					}
				},
				"required": [
					"state",
					"reason",
					"connectedAt",
					"lastHeartbeatAt",
					"reconnectAttempts",
					"nextRetryAt"
				]
			},
			"SessionState": {
				"type": "string",
				"enum": [
					"Absent",
					"Connecting",
					"ActiveReconciling",
					"Active",
					"Reconnecting",
					"DisconnectedConflict",
					"BrokerUnavailable",
					"IdleEvicted"
				]
			},
			"PlaceTradingOrderRouteResponse": {
				"anyOf": [
					{
						"$ref": "#/components/schemas/PlaceTradingOrderResponse"
					},
					{
						"$ref": "#/components/schemas/UnknownTradingExecutionOutcome"
					}
				]
			},
			"PlaceTradingOrderResponse": {
				"type": "object",
				"properties": {
					"order": {
						"$ref": "#/components/schemas/Order"
					},
					"execution": {
						"$ref": "#/components/schemas/Execution"
					},
					"risk": {
						"$ref": "#/components/schemas/RiskOutcome"
					}
				},
				"required": [
					"order",
					"execution",
					"risk"
				]
			},
			"Execution": {
				"type": "object",
				"properties": {
					"status": {
						"$ref": "#/components/schemas/ExecutionStatus"
					},
					"clOrdId": {
						"type": "string"
					},
					"orderId": {
						"type": "string",
						"nullable": true
					},
					"fills": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/Fill"
						}
					},
					"filledVolume": {
						"type": "number"
					},
					"positionId": {
						"type": "string",
						"nullable": true
					},
					"rejectReason": {
						"type": "string",
						"nullable": true
					}
				},
				"required": [
					"status",
					"clOrdId",
					"orderId",
					"fills",
					"filledVolume",
					"positionId",
					"rejectReason"
				]
			},
			"ExecutionStatus": {
				"type": "string",
				"enum": [
					"filled",
					"partiallyFilled",
					"pending",
					"rejected",
					"cancelled",
					"expired",
					"unknown"
				]
			},
			"Fill": {
				"type": "object",
				"properties": {
					"volume": {
						"type": "number"
					},
					"price": {
						"type": "number"
					},
					"executedAt": {
						"type": "string"
					}
				},
				"required": [
					"volume",
					"price",
					"executedAt"
				]
			},
			"RiskOutcome": {
				"type": "object",
				"properties": {
					"checksPassed": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/RiskCheckName"
						}
					},
					"bracketExemptionApplied": {
						"type": "boolean"
					}
				},
				"required": [
					"checksPassed",
					"bracketExemptionApplied"
				]
			},
			"UnknownTradingExecutionOutcome": {
				"type": "object",
				"properties": {
					"execution": {
						"type": "object",
						"properties": {
							"status": {
								"type": "string",
								"enum": [
									"unknown"
								]
							},
							"clOrdId": {
								"type": "string"
							},
							"orderId": {
								"type": "string",
								"nullable": true
							},
							"fills": {
								"type": "array",
								"items": {
									"$ref": "#/components/schemas/Fill"
								}
							},
							"filledVolume": {
								"type": "number"
							},
							"positionId": {
								"type": "string",
								"nullable": true
							},
							"rejectReason": {
								"type": "string",
								"nullable": true
							}
						},
						"required": [
							"status",
							"clOrdId",
							"orderId",
							"fills",
							"filledVolume",
							"positionId",
							"rejectReason"
						]
					}
				},
				"required": [
					"execution"
				]
			},
			"PlaceTradingOrderRequest": {
				"type": "object",
				"properties": {
					"serverId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"traderId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					},
					"symbol": {
						"type": "string",
						"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"
					},
					"side": {
						"$ref": "#/components/schemas/OrderSide"
					},
					"type": {
						"$ref": "#/components/schemas/OrderType"
					},
					"timeInForce": {
						"$ref": "#/components/schemas/TimeInForce"
					},
					"volume": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"price": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"stopPrice": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"positionId": {
						"type": "string"
					},
					"comment": {
						"type": "string",
						"maxLength": 100
					},
					"expireTime": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"serverId",
					"traderId",
					"env",
					"symbol",
					"side",
					"type",
					"volume"
				]
			},
			"ModifyTradingOrderRouteResponse": {
				"anyOf": [
					{
						"$ref": "#/components/schemas/ModifyTradingOrderResponse"
					},
					{
						"$ref": "#/components/schemas/UnknownTradingExecutionOutcome"
					}
				]
			},
			"ModifyTradingOrderResponse": {
				"type": "object",
				"properties": {
					"order": {
						"$ref": "#/components/schemas/Order"
					},
					"execution": {
						"$ref": "#/components/schemas/Execution"
					}
				},
				"required": [
					"order",
					"execution"
				]
			},
			"ModifyTradingOrderRequest": {
				"type": "object",
				"properties": {
					"serverId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"traderId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					},
					"orderId": {
						"type": "string"
					},
					"clOrdId": {
						"type": "string"
					},
					"volume": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"price": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"stopPrice": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					}
				},
				"required": [
					"serverId",
					"traderId",
					"env"
				]
			},
			"CancelTradingOrderRouteResponse": {
				"anyOf": [
					{
						"$ref": "#/components/schemas/CancelTradingOrderResponse"
					},
					{
						"$ref": "#/components/schemas/UnknownTradingExecutionOutcome"
					}
				]
			},
			"CancelTradingOrderResponse": {
				"type": "object",
				"properties": {
					"order": {
						"$ref": "#/components/schemas/Order"
					},
					"execution": {
						"$ref": "#/components/schemas/Execution"
					}
				},
				"required": [
					"order",
					"execution"
				]
			},
			"CancelTradingOrderRequest": {
				"type": "object",
				"properties": {
					"serverId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"traderId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					},
					"orderId": {
						"type": "string"
					},
					"clOrdId": {
						"type": "string"
					}
				},
				"required": [
					"serverId",
					"traderId",
					"env"
				]
			},
			"CloseTradingPositionRouteResponse": {
				"anyOf": [
					{
						"$ref": "#/components/schemas/CloseTradingPositionResponse"
					},
					{
						"$ref": "#/components/schemas/UnknownTradingExecutionOutcome"
					}
				]
			},
			"CloseTradingPositionResponse": {
				"type": "object",
				"properties": {
					"position": {
						"type": "object",
						"nullable": true,
						"properties": {
							"positionId": {
								"type": "string"
							},
							"symbol": {
								"type": "string"
							},
							"side": {
								"$ref": "#/components/schemas/OrderSide"
							},
							"volume": {
								"type": "number"
							},
							"entryPrice": {
								"type": "number"
							},
							"currentPrice": {
								"type": "number",
								"nullable": true
							},
							"unrealisedPnl": {
								"$ref": "#/components/schemas/Money"
							},
							"swap": {
								"type": "number",
								"nullable": true
							},
							"commission": {
								"type": "number",
								"nullable": true
							},
							"stopLoss": {
								"type": "number",
								"nullable": true
							},
							"takeProfit": {
								"type": "number",
								"nullable": true
							},
							"openedAt": {
								"type": "string"
							},
							"linkedOrderIds": {
								"type": "array",
								"items": {
									"type": "string"
								}
							},
							"divergence": {
								"$ref": "#/components/schemas/PositionDivergence"
							},
							"divergenceNote": {
								"type": "string",
								"nullable": true
							},
							"confirmedAt": {
								"type": "string"
							}
						},
						"required": [
							"positionId",
							"symbol",
							"side",
							"volume",
							"entryPrice",
							"currentPrice",
							"unrealisedPnl",
							"swap",
							"commission",
							"stopLoss",
							"takeProfit",
							"openedAt",
							"linkedOrderIds",
							"divergence",
							"divergenceNote",
							"confirmedAt"
						]
					},
					"execution": {
						"$ref": "#/components/schemas/Execution"
					},
					"realisedPnl": {
						"$ref": "#/components/schemas/Money"
					},
					"cancelledLinkedOrders": {
						"type": "array",
						"items": {
							"type": "string"
						}
					}
				},
				"required": [
					"position",
					"execution",
					"realisedPnl",
					"cancelledLinkedOrders"
				]
			},
			"CloseTradingPositionRequest": {
				"type": "object",
				"properties": {
					"serverId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"traderId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					},
					"positionId": {
						"type": "string"
					},
					"volume": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"comment": {
						"type": "string",
						"maxLength": 100
					}
				},
				"required": [
					"serverId",
					"traderId",
					"env",
					"positionId"
				]
			},
			"CloseAllTradingPositionsRouteResponse": {
				"anyOf": [
					{
						"$ref": "#/components/schemas/CloseAllTradingPositionsResponse"
					},
					{
						"$ref": "#/components/schemas/UnknownTradingExecutionOutcome"
					}
				]
			},
			"CloseAllTradingPositionsResponse": {
				"type": "object",
				"properties": {
					"results": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/ClosePositionResult"
						}
					},
					"summary": {
						"type": "object",
						"properties": {
							"closed": {
								"type": "integer",
								"minimum": 0
							},
							"pending": {
								"type": "integer",
								"minimum": 0
							},
							"failed": {
								"type": "integer",
								"minimum": 0
							}
						},
						"required": [
							"closed",
							"pending",
							"failed"
						]
					},
					"asOf": {
						"type": "string"
					}
				},
				"required": [
					"results",
					"summary",
					"asOf"
				]
			},
			"ClosePositionResult": {
				"type": "object",
				"properties": {
					"positionId": {
						"type": "string"
					},
					"symbol": {
						"type": "string"
					},
					"outcome": {
						"$ref": "#/components/schemas/ClosePositionOutcome"
					},
					"execution": {
						"type": "object",
						"nullable": true,
						"properties": {
							"status": {
								"$ref": "#/components/schemas/ExecutionStatus"
							},
							"clOrdId": {
								"type": "string"
							},
							"orderId": {
								"type": "string",
								"nullable": true
							},
							"fills": {
								"type": "array",
								"items": {
									"$ref": "#/components/schemas/Fill"
								}
							},
							"filledVolume": {
								"type": "number"
							},
							"positionId": {
								"type": "string",
								"nullable": true
							},
							"rejectReason": {
								"type": "string",
								"nullable": true
							}
						},
						"required": [
							"status",
							"clOrdId",
							"orderId",
							"fills",
							"filledVolume",
							"positionId",
							"rejectReason"
						]
					},
					"realisedPnl": {
						"type": "object",
						"nullable": true,
						"properties": {
							"amount": {
								"type": "number"
							},
							"currency": {
								"type": "string"
							},
							"converted": {
								"type": "object",
								"nullable": true,
								"properties": {
									"amount": {
										"type": "number"
									},
									"currency": {
										"type": "string",
										"enum": [
											"USD"
										]
									},
									"rate": {
										"type": "number"
									},
									"rateSource": {
										"type": "string"
									}
								},
								"required": [
									"amount",
									"currency",
									"rate",
									"rateSource"
								]
							}
						},
						"required": [
							"amount",
							"currency",
							"converted"
						]
					},
					"error": {
						"type": "object",
						"nullable": true,
						"properties": {
							"code": {
								"$ref": "#/components/schemas/TradingExecutionErrorCode"
							},
							"message": {
								"type": "string"
							},
							"details": {
								"$ref": "#/components/schemas/TradingExecutionErrorDetails"
							}
						},
						"required": [
							"code",
							"message"
						]
					}
				},
				"required": [
					"positionId",
					"symbol",
					"outcome",
					"execution",
					"realisedPnl",
					"error"
				]
			},
			"ClosePositionOutcome": {
				"type": "string",
				"enum": [
					"closed",
					"pending",
					"failed"
				]
			},
			"CloseAllTradingPositionsRequest": {
				"type": "object",
				"properties": {
					"serverId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"traderId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					},
					"symbol": {
						"type": "string",
						"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"
					},
					"comment": {
						"type": "string",
						"maxLength": 100
					}
				},
				"required": [
					"serverId",
					"traderId",
					"env"
				]
			},
			"ReconnectTradingSessionResponse": {
				"type": "object",
				"properties": {
					"state": {
						"$ref": "#/components/schemas/SessionState"
					},
					"target": {
						"type": "string",
						"enum": [
							"trade",
							"quote",
							"both"
						]
					},
					"backoffPreserved": {
						"type": "boolean"
					}
				},
				"required": [
					"state",
					"target",
					"backoffPreserved"
				]
			},
			"ReconnectTradingSessionRequest": {
				"type": "object",
				"properties": {
					"serverId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"traderId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					},
					"target": {
						"type": "string",
						"enum": [
							"trade",
							"quote",
							"both"
						],
						"default": "both"
					}
				},
				"required": [
					"serverId",
					"traderId",
					"env"
				]
			},
			"PlaceStageTradingOrderRequest": {
				"type": "object",
				"properties": {
					"accountId": {
						"type": "string",
						"minLength": 1,
						"description": "The opaque accountId the account list on this stage returned for the account"
					},
					"symbol": {
						"type": "string",
						"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"
					},
					"side": {
						"$ref": "#/components/schemas/OrderSide"
					},
					"type": {
						"$ref": "#/components/schemas/OrderType"
					},
					"timeInForce": {
						"$ref": "#/components/schemas/TimeInForce"
					},
					"volume": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"price": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true,
						"requiredWhen": {
							"type": "LIMIT"
						}
					},
					"stopPrice": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true,
						"requiredWhen": {
							"type": "STOP"
						}
					},
					"positionId": {
						"type": "string"
					},
					"comment": {
						"type": "string",
						"maxLength": 100
					},
					"expireTime": {
						"type": "string",
						"format": "date-time",
						"requiredWhen": {
							"timeInForce": "GTD"
						}
					}
				},
				"required": [
					"accountId",
					"symbol",
					"side",
					"type",
					"volume"
				],
				"additionalProperties": false
			},
			"ModifyStageTradingOrderRequest": {
				"type": "object",
				"properties": {
					"accountId": {
						"type": "string",
						"minLength": 1,
						"description": "The opaque accountId the account list on this stage returned for the account"
					},
					"orderId": {
						"type": "string"
					},
					"clOrdId": {
						"type": "string"
					},
					"volume": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"price": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"stopPrice": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					}
				},
				"required": [
					"accountId"
				],
				"additionalProperties": false
			},
			"CancelStageTradingOrderRequest": {
				"type": "object",
				"properties": {
					"accountId": {
						"type": "string",
						"minLength": 1,
						"description": "The opaque accountId the account list on this stage returned for the account"
					},
					"orderId": {
						"type": "string"
					},
					"clOrdId": {
						"type": "string"
					}
				},
				"required": [
					"accountId"
				],
				"additionalProperties": false
			},
			"CloseStageTradingPositionRequest": {
				"type": "object",
				"properties": {
					"accountId": {
						"type": "string",
						"minLength": 1,
						"description": "The opaque accountId the account list on this stage returned for the account"
					},
					"positionId": {
						"type": "string"
					},
					"volume": {
						"type": "number",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"comment": {
						"type": "string",
						"maxLength": 100
					}
				},
				"required": [
					"accountId",
					"positionId"
				],
				"additionalProperties": false
			},
			"CloseAllStageTradingPositionsRequest": {
				"type": "object",
				"properties": {
					"accountId": {
						"type": "string",
						"minLength": 1,
						"description": "The opaque accountId the account list on this stage returned for the account"
					},
					"symbol": {
						"type": "string",
						"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"
					},
					"comment": {
						"type": "string",
						"maxLength": 100
					}
				},
				"required": [
					"accountId"
				],
				"additionalProperties": false
			},
			"ReconnectStageTradingSessionRequest": {
				"type": "object",
				"properties": {
					"accountId": {
						"type": "string",
						"minLength": 1,
						"description": "The opaque accountId the account list on this stage returned for the account"
					},
					"target": {
						"type": "string",
						"enum": [
							"trade",
							"quote",
							"both"
						],
						"default": "both"
					}
				},
				"required": [
					"accountId"
				],
				"additionalProperties": false
			},
			"AccountAccessTokenResponse": {
				"type": "object",
				"properties": {
					"credentialId": {
						"type": "string",
						"description": "The broker's own identifier for this credential. Not the credential itself — safe to log and to use to correlate a later support query with this specific issuance."
					},
					"apiKey": {
						"type": "string",
						"description": "Secret material — the part the client API is told on every request, identifying the session. Transmitted each call, so it is the weaker half. Never appears in a log line, stored state, or an error payload; this success body is the one deliberate exception."
					},
					"signingSecret": {
						"type": "string",
						"description": "Secret material — the key the client signs each request with. It is NEVER transmitted: it keys the signature, and a client that sends it instead of signing with it has disclosed it. Holding both parts is what grants access, so this is the half worth protecting hardest. Never appears in a log line, stored state, or an error payload; this success body is the one deliberate exception."
					},
					"kind": {
						"$ref": "#/components/schemas/AccountAccessCredentialKind"
					},
					"expiresAt": {
						"type": "string",
						"description": "ISO-8601 instant the credential stops working. Nothing in this system shortens or extends that lifetime once the credential is issued."
					},
					"clientApiUrl": {
						"type": "string",
						"format": "uri",
						"description": "The broker's client API address for the stage that served this request. Never derive this from the address this backend calls to mint the credential — the two are configured independently and are not a transform of one another."
					}
				},
				"required": [
					"credentialId",
					"apiKey",
					"signingSecret",
					"kind",
					"expiresAt",
					"clientApiUrl"
				]
			},
			"AccountAccessCredentialKind": {
				"type": "string",
				"enum": [
					"API_KEY_SECRET_PAIR"
				],
				"description": "The shape of the credential material below. `API_KEY_SECRET_PAIR` is two independent secret parts (`apiKey` + `signingSecret`) used together to sign a request against the client API. A future platform whose broker issues, say, a single bearer token would carry a different value here rather than reusing this one."
			},
			"AccountAccessTokenRequest": {
				"type": "object",
				"properties": {
					"serverId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"traderId": {
						"type": "integer",
						"minimum": 0,
						"exclusiveMinimum": true
					},
					"env": {
						"type": "string",
						"enum": [
							"demo",
							"live"
						]
					}
				},
				"required": [
					"serverId",
					"traderId",
					"env"
				]
			},
			"StageAccountAccessTokenRequest": {
				"type": "object",
				"properties": {
					"accountId": {
						"type": "string",
						"minLength": 1,
						"description": "The opaque accountId the account list on this stage returned for the account"
					}
				},
				"required": [
					"accountId"
				],
				"additionalProperties": false
			},
			"GetTradingUserResponse": {
				"type": "object",
				"properties": {
					"user": {
						"$ref": "#/components/schemas/TradingUserCrm"
					}
				},
				"required": [
					"user"
				]
			},
			"TradingUserCrm": {
				"type": "object",
				"properties": {
					"brand": {
						"type": "string",
						"enum": [
							"axiory",
							"purpleTrading",
							"fintokei"
						]
					},
					"brandClientId": {
						"type": "string",
						"minLength": 1
					},
					"email": {
						"type": "string"
					},
					"firstName": {
						"type": "string",
						"nullable": true
					},
					"lastName": {
						"type": "string",
						"nullable": true
					},
					"userStatus": {
						"type": "string",
						"enum": [
							"active",
							"pending",
							"closed",
							"dormant"
						]
					},
					"language": {
						"type": "string",
						"nullable": true
					},
					"partnerCode": {
						"type": "string",
						"nullable": true
					},
					"country": {
						"type": "string",
						"nullable": true
					},
					"dateOfBirth": {
						"type": "string",
						"nullable": true
					},
					"registeredDate": {
						"type": "string",
						"nullable": true
					},
					"phone": {
						"type": "string",
						"nullable": true
					},
					"completedStage": {
						"type": "string",
						"nullable": true
					},
					"gracePeriodStatus": {
						"type": "string",
						"nullable": true
					},
					"crmWorkspace": {
						"type": "string",
						"nullable": true,
						"enum": [
							"asia",
							"glob",
							"tradit",
							null
						]
					}
				},
				"required": [
					"brand",
					"brandClientId",
					"email",
					"userStatus"
				]
			}
		}
	},
	"security": [
		{
			"apiKey": []
		},
		{
			"bearerAuth": []
		}
	]
}