{
  "openapi": "3.1.0",
  "info": {
    "title": "Cardiv Market Maker API",
    "version": "1.0.0",
    "summary": "External market-maker surface for the Cardiv CLOB on Canton.",
    "description": "Non-custodial CLOB on Canton. Assets remain in the market maker party and are\nlocked in place by an allocation contract for the life of an order.\n\nOrdering is two-legged and cannot be collapsed into one call:\n\n  1. POST /orders          Cardiv prepares the transaction, returns a hash\n  2. sign(hash)            the client signs locally, with a key Cardiv never sees\n  3. POST {submitUrl}      Calden submits it to the ledger\n\nCancels follow the same three steps. The submit in step 3 goes to the\nCalden server, not Cardiv, and needs no credential: it is authorised by the\none-time submitToken plus a signature matching the hash Calden cached.\n\nConstraints relevant to integration design:\n  - No amend. Re-pricing is cancel plus place.\n  - No batching. Canton rejects multi-command prepare.\n  - Transfer preapprovals are asserted by the contract at placement and\n    again for both sides at settlement.\n  - contractId rotates on partial fill; orderId is stable.\n",
    "contact": {
      "name": "WolfEdge Labs",
      "email": "tools@wolfedgelabs.com"
    }
  },
  "servers": [
    {
      "url": "https://api.beta.cardiv.xyz/api/trade/v1",
      "description": "Devnet (integration environment)"
    }
  ],
  "tags": [
    {
      "name": "Market data",
      "description": "Public. No credential required."
    },
    {
      "name": "Account",
      "description": "The account party, orders and balances."
    },
    {
      "name": "Trading",
      "description": "Prepare an order or a cancel for signing."
    },
    {
      "name": "Submit",
      "description": "Calden. Different host, no credential."
    }
  ],
  "security": [
    {
      "ApiKeyBearer": []
    },
    {
      "ApiKeyHeader": []
    }
  ],
  "paths": {
    "/pairs": {
      "get": {
        "tags": [
          "Market data"
        ],
        "summary": "Enabled pairs and their limits",
        "security": [],
        "description": "Call at startup. minQuoteAmount is the value to respect when sizing orders.",
        "responses": {
          "200": {
            "description": "Enabled pairs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "pairs": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Pair"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "listPairs"
      }
    },
    "/orderbook/{pair}": {
      "get": {
        "tags": [
          "Market data"
        ],
        "summary": "Order book snapshot",
        "security": [],
        "description": "Primary market-data source. Poll at 1 to 2 second intervals; faster is wasteful because this reads a database projection, not the ledger.",
        "parameters": [
          {
            "name": "pair",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "URL-encoded, e.g. CBTC%2FCC",
            "example": "CBTC%2FCC"
          },
          {
            "name": "depth",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Levels per side."
          }
        ],
        "responses": {
          "200": {
            "description": "Book snapshot.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "pair": {
                          "type": "string"
                        },
                        "bids": {
                          "type": "array",
                          "description": "Descending by price. Each entry is [price, quantity] as strings.",
                          "items": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "minItems": 2,
                            "maxItems": 2
                          }
                        },
                        "asks": {
                          "type": "array",
                          "description": "Ascending by price. Each entry is [price, quantity] as strings.",
                          "items": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "minItems": 2,
                            "maxItems": 2
                          }
                        },
                        "asOf": {
                          "type": "object",
                          "properties": {
                            "updateId": {
                              "type": [
                                "integer",
                                "null"
                              ]
                            },
                            "sequence": {
                              "type": "integer"
                            },
                            "source": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "getOrderBook"
      }
    },
    "/trades": {
      "get": {
        "tags": [
          "Market data"
        ],
        "summary": "Recent public trades",
        "security": [],
        "parameters": [
          {
            "name": "pair",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "example": "CBTC/CC"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recent prints.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "pair": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "trades": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "tradeId": {
                                "type": "string"
                              },
                              "price": {
                                "type": "string"
                              },
                              "quantity": {
                                "type": "string"
                              },
                              "executedAt": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          }
                        },
                        "nextCursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "listTrades"
      }
    },
    "/account": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Your account and limits",
        "description": "First call to make. Confirms the key works and reports the policy in force, including the clientOrderId prefix you must use.",
        "responses": {
          "200": {
            "description": "Account and policy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "slug": {
                          "type": "string",
                          "description": "The clientOrderId prefix, without the hyphen."
                        },
                        "partyId": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "ACTIVE",
                            "SUSPENDED",
                            "DISABLED"
                          ]
                        },
                        "feeExempt": {
                          "type": "boolean",
                          "description": "True means zero fee on place, cancel and fill."
                        },
                        "clientOrderIdPrefix": {
                          "type": "string",
                          "examples": [
                            "acme-"
                          ],
                          "description": "Every submitted clientOrderId must start with this."
                        },
                        "limits": {
                          "type": "object",
                          "properties": {
                            "allowedPairs": {
                              "description": "Array of pair names, or the string \"all\".",
                              "oneOf": [
                                {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                {
                                  "type": "string",
                                  "const": "all"
                                }
                              ]
                            },
                            "maxOpenOrders": {
                              "type": [
                                "integer",
                                "null"
                              ],
                              "description": "Cap on resting orders. Null means uncapped."
                            },
                            "ordersPerMinute": {
                              "type": [
                                "integer",
                                "null"
                              ]
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request. Do not retry unchanged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Account suspended, or the pair is not enabled for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or open-order cap reached. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Safe to retry a prepare with the same clientOrderId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "getAccount"
      }
    },
    "/orders": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Your orders",
        "description": "Returns only orders belonging to the market maker party; there is no endpoint exposing other participants' orders. Aggregate activity of other participants is visible through the public market-data endpoints (GET /orderbook, GET /trades). Used to reconcile fills and to recover after a submission whose connection dropped.",
        "parameters": [
          {
            "name": "pair",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by pair."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "OPEN returns all resting states (OPEN, PARTIALLY_FILLED, PENDING_TRIGGER)."
          },
          {
            "name": "side",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "BUY",
                "SELL"
              ]
            },
            "description": "Filter by side."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Lower bound on order creation time, ISO 8601."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Upper bound on order creation time, ISO 8601."
          },
          {
            "name": "refreshCalden",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            },
            "description": "When true (the default) the wallet service is re-queried, which can add tens of seconds. Polling loops should set false."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Your orders.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "orders": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Order"
                          }
                        },
                        "pagination": {
                          "type": "object",
                          "properties": {
                            "limit": {
                              "type": "integer"
                            },
                            "cursor": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "hasMore": {
                              "type": "boolean"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request. Do not retry unchanged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Account suspended, or the pair is not enabled for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or open-order cap reached. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Safe to retry a prepare with the same clientOrderId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "listOrders"
      },
      "post": {
        "tags": [
          "Trading"
        ],
        "summary": "Prepare an order for signing",
        "description": "Step 1 of 3. Validates the order, builds the Canton transaction and has it\nprepared against the ledger. NOTHING IS ON THE BOOK when this returns.\n\nNext: sign data.signing.preparedTransactionHash and POST the signature to\ndata.signing.submitUrl (see the Submit tag).\n\nThe prepared transaction has a 5 minute TTL. Prepare only what the client intends\nto sign immediately.\n\nTypical latency 10 to 13 seconds against a 30 second server ceiling.\n\nSERIALISE PER PARTY. Preparing a second order while a previous one is still\nawaiting ledger confirmation can be rejected with LEDGER_COMMAND_REJECTED\n(\"Calden is still waiting for ledger confirmation\"). Reproduced under network\ndegradation; no safe concurrency limit has been established under healthy\nconditions. Submit, confirm via GET /orders, then prepare the next.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlaceOrderRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Prepared and already resting (rare).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PlaceOrderResponse"
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Prepared. Awaiting your signature.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PlaceOrderResponse"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request. Do not retry unchanged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Account suspended, or the pair is not enabled for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or open-order cap reached. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Safe to retry a prepare with the same clientOrderId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "prepareOrder"
      }
    },
    "/orders/{orderId}": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Single order by orderId",
        "description": "Recovery primitive. After a failed, timed-out or lost submission, reports whether that specific order reached the book without listing the whole set. Reads directly and never triggers a wallet-service refresh. An orderId that does not exist, or belongs to another participant, returns 404.",
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The order.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "order": {
                          "$ref": "#/components/schemas/Order"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request. Do not retry unchanged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Account suspended, or the pair is not enabled for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such order for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or open-order cap reached. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Safe to retry a prepare with the same clientOrderId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "getOrder"
      }
    },
    "/orders/{contractId}/cancel": {
      "post": {
        "tags": [
          "Trading"
        ],
        "summary": "Prepare a cancel for signing",
        "description": "Same three-step shape as placement. Pass the CURRENT contractId: it rotates on partial fill, so re-read GET /orders if a cancel returns CONTRACT_NOT_FOUND. To cancel many orders, call this concurrently; there is no batch endpoint because Canton has no batch transaction.",
        "parameters": [
          {
            "name": "contractId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "Free text, recorded for audit."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Prepared.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "cancelled": {
                          "type": "boolean"
                        },
                        "order": {
                          "$ref": "#/components/schemas/Order"
                        },
                        "signing": {
                          "$ref": "#/components/schemas/SigningEnvelope"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Prepared, awaiting signature.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "cancelled": {
                          "type": "boolean"
                        },
                        "signing": {
                          "$ref": "#/components/schemas/SigningEnvelope"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request. Do not retry unchanged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Account suspended, or the pair is not enabled for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such order, or the contractId is stale after a partial fill.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Already filled or already cancelled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or open-order cap reached. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Safe to retry a prepare with the same clientOrderId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "prepareCancel"
      }
    },
    "/balances": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Balances (own party)",
        "description": "The party is resolved from the API key; one account is bound to exactly one party, so no parameter is required or accepted. Reads the ledger: startup and slow timer only, never inside a quote loop.",
        "responses": {
          "200": {
            "$ref": "#/components/responses/Balances"
          },
          "400": {
            "description": "Invalid request. Do not retry unchanged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Account suspended, or the pair is not enabled for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or open-order cap reached. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Safe to retry a prepare with the same clientOrderId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "getOwnBalances"
      }
    },
    "/orders/cancel": {
      "post": {
        "tags": [
          "Trading"
        ],
        "summary": "Not supported",
        "description": "Deliberately absent. Canton rejects multi-command preparation, so a batch cancel could only ever return N signing requests, never one transaction cancelling N orders. Cancel individually and concurrently.",
        "deprecated": true,
        "responses": {
          "404": {
            "description": "Always returns NOT_SUPPORTED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "bulkCancelNotSupported"
      }
    },
    "/submit": {
      "post": {
        "tags": [
          "Submit"
        ],
        "summary": "Submit a signed transaction (Calden host)",
        "security": [],
        "servers": [
          {
            "url": "{submitUrl}",
            "description": "Use the absolute submitUrl returned by the prepare call. This URL must not be constructed by the client.",
            "variables": {
              "submitUrl": {
                "default": "https://beta.app.calden.xyz"
              }
            }
          }
        ],
        "description": "Step 3 of 3. POST to the absolute submitUrl from the prepare response.\nThis is the CALDEN host, not Cardiv, and takes no API key: authorisation is\nthe one-time submitToken plus a signature matching the hash Calden cached.\n\nAllow at least 120 seconds of client timeout. Submission queues behind a\ntraffic lock and retries consensus timeouts internally; a 30 second timeout\nwill abandon transactions that go on to commit.\n\nOn a timeout or 5xx, DO NOT blindly retry. Read GET /orders first: the\ntransaction may have committed despite the dropped connection.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted. The order appears in GET /orders a second or two later."
          },
          "410": {
            "description": "CACHE_EXPIRED: submitted past the 5 minute prepared-transaction TTL. Re-prepare.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. The body carries the limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Ledger-side failure. Calden currently collapses these into one generic message, so a stalled sequencer and a rejected signature look identical here. Check GET /orders before assuming anything.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "No definite answer from the ledger. The transaction may or may not have committed. Check GET /orders.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "submitSignedTransaction"
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization: Bearer mm_ak_<prefix>.<secret>. The part before the dot is a public handle, safe to log. The part after is the secret."
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Equivalent to the bearer form."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "ok",
          "error"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Machine-readable. Branch on this, not on message.",
                "enum": [
                  "MISSING_API_KEY",
                  "INVALID_API_KEY",
                  "API_KEY_REVOKED",
                  "API_KEY_EXPIRED",
                  "MARKET_MAKER_SUSPENDED",
                  "PAIR_NOT_ALLOWED",
                  "INVALID_CLIENT_ORDER_ID",
                  "MAX_OPEN_ORDERS",
                  "RATE_LIMITED",
                  "VALIDATION_ERROR",
                  "INSUFFICIENT_BALANCE",
                  "LEDGER_COMMAND_REJECTED",
                  "CACHE_EXPIRED",
                  "CONTRACT_NOT_FOUND",
                  "ORDER_ALREADY_FILLED",
                  "ORDER_ALREADY_CANCELLED",
                  "NOT_SUPPORTED",
                  "AUTH_NOT_CONFIGURED",
                  "INTERNAL_ERROR"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable. May change; do not parse."
              },
              "expectedPrefix": {
                "type": "string",
                "description": "On INVALID_CLIENT_ORDER_ID: the required identifier prefix."
              },
              "allowedPairs": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "On PAIR_NOT_ALLOWED."
              },
              "limit": {
                "type": "integer",
                "description": "On RATE_LIMITED: requests allowed per window."
              },
              "openOrders": {
                "type": "integer",
                "description": "On MAX_OPEN_ORDERS: the current resting count."
              },
              "maxOpenOrders": {
                "type": "integer",
                "description": "On MAX_OPEN_ORDERS: the configured cap."
              }
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "requestId": {
                "type": "string"
              }
            }
          }
        }
      },
      "Pair": {
        "type": "object",
        "properties": {
          "pair": {
            "type": "string",
            "examples": [
              "CBTC/CC"
            ],
            "description": "Use this verbatim as the `pair` field when placing orders. URL-encode it in path parameters."
          },
          "base": {
            "type": "string",
            "examples": [
              "CBTC"
            ],
            "description": "Instrument the quantity is denominated in."
          },
          "quote": {
            "type": "string",
            "examples": [
              "CC"
            ],
            "description": "Instrument the price is denominated in."
          },
          "minQuoteAmount": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "5"
            ],
            "description": "Minimum order notional (price x quantity) in the quote instrument. Placements below this are rejected. A fill leaving a smaller residual expires that residual rather than resting it."
          },
          "feeSymbol": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "CC"
            ],
            "description": "Instrument any provider fee is charged in. Zero for fee-exempt accounts."
          }
        }
      },
      "Order": {
        "type": "object",
        "properties": {
          "contractId": {
            "type": "string",
            "description": "On-ledger contract id. ROTATES on partial fill: the residual is a new contract. Do not cache this as an order identity."
          },
          "orderId": {
            "type": "string",
            "description": "Stable across partial fills. The correct order tracking key."
          },
          "pair": {
            "type": "string",
            "examples": [
              "CBTC/cETH"
            ]
          },
          "side": {
            "type": "string",
            "enum": [
              "BUY",
              "SELL"
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "LIMIT",
              "MARKET",
              "STOP_LOSS"
            ]
          },
          "price": {
            "type": [
              "string",
              "null"
            ]
          },
          "quantity": {
            "type": "string",
            "description": "Original size in the base instrument."
          },
          "filled": {
            "type": "string",
            "description": "Filled so far, in the base instrument. Remaining is quantity minus filled."
          },
          "status": {
            "type": "string",
            "enum": [
              "OPEN",
              "PARTIALLY_FILLED",
              "FILLED",
              "CANCELLED",
              "EXPIRED",
              "PENDING_TRIGGER",
              "FAILED"
            ],
            "description": "OPEN and PARTIALLY_FILLED are resting and cancellable."
          },
          "stopPrice": {
            "type": [
              "string",
              "null"
            ]
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Created at."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "correlationId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Quote this in support tickets."
          }
        }
      },
      "SigningEnvelope": {
        "type": "object",
        "description": "Everything needed to sign and submit. Present whenever requiresSignature is true.",
        "properties": {
          "requiresSignature": {
            "type": "boolean",
            "description": "Always true on this API. Cardiv cannot submit on behalf of the market maker."
          },
          "preparedTransactionHash": {
            "type": "string",
            "description": "Base64. SIGN THE RAW BYTES of this after base64-decoding it. Do not re-hash, do not prefix, do not sign the base64 string itself."
          },
          "hashingSchemeVersion": {
            "type": "string",
            "examples": [
              "HASHING_SCHEME_VERSION_V2"
            ],
            "description": "Echo back verbatim in the submit body."
          },
          "submitUrl": {
            "type": "string",
            "format": "uri",
            "description": "Absolute URL on the CALDEN host, not Cardiv. POST the signed payload here."
          },
          "submitToken": {
            "type": "string",
            "description": "One-time authorisation for this submission. 20 minute TTL, but the 5 minute prepared-transaction cache always expires first."
          },
          "commandId": {
            "type": "string",
            "description": "Echo back verbatim in the submit body."
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "PENDING_SIGNATURE"
            ]
          },
          "signingUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Browser signing page. Not used by API integrators."
          },
          "prepared": {
            "type": [
              "object",
              "null"
            ],
            "description": "Raw prepared transaction. Not needed for submission."
          }
        }
      },
      "PlaceOrderRequest": {
        "type": "object",
        "required": [
          "pair",
          "side",
          "type",
          "quantity"
        ],
        "properties": {
          "pair": {
            "type": "string",
            "examples": [
              "CBTC/CC"
            ],
            "description": "Must appear in GET /pairs and be permitted for the account. Alias: tradingPair."
          },
          "side": {
            "type": "string",
            "enum": [
              "BUY",
              "SELL"
            ],
            "description": "BUY locks quote instrument, SELL locks base. Alias: orderType."
          },
          "type": {
            "type": "string",
            "enum": [
              "LIMIT",
              "MARKET",
              "STOP_LOSS"
            ],
            "default": "LIMIT",
            "description": "Alias: orderMode."
          },
          "price": {
            "type": "string",
            "pattern": "^[0-9]+(\\.[0-9]{1,10})?$",
            "description": "Required for LIMIT, ignored for MARKET. Quote instrument per unit of base. Sent and returned as a string, never a JSON number: values carry more precision than a double holds, and an over-scale value is rejected rather than rounded. Maximum 10 decimal places.",
            "examples": [
              "62500.00"
            ]
          },
          "quantity": {
            "type": "string",
            "pattern": "^[0-9]+(\\.[0-9]{1,10})?$",
            "description": "Order size in the base instrument. price x quantity must be at least the pair minQuoteAmount. Sent and returned as a string, never a JSON number: values carry more precision than a double holds, and an over-scale value is rejected rather than rounded. Maximum 10 decimal places.",
            "examples": [
              "0.01"
            ]
          },
          "clientOrderId": {
            "type": "string",
            "maxLength": 120,
            "description": "Optional. If supplied it MUST start with the account slug and a hyphen, because order ids are unique across the whole venue. Omit it and one is generated. Placement is idempotent on this value, so a prepare that times out can be safely retried with the same id.",
            "examples": [
              "acme-q-1723640000-bid"
            ]
          },
          "stopPrice": {
            "type": "string",
            "pattern": "^[0-9]+(\\.[0-9]{1,10})?$",
            "description": "Required for STOP_LOSS. Alias: stopLossPrice. Sent and returned as a string, never a JSON number: values carry more precision than a double holds, and an over-scale value is rejected rather than rounded. Maximum 10 decimal places.",
            "examples": [
              "58000.00"
            ]
          }
        }
      },
      "PlaceOrderResponse": {
        "type": "object",
        "properties": {
          "order": {
            "type": "object",
            "properties": {
              "clientOrderId": {
                "type": "string"
              },
              "pair": {
                "type": "string"
              },
              "side": {
                "type": "string",
                "enum": [
                  "BUY",
                  "SELL"
                ]
              },
              "type": {
                "type": "string"
              },
              "price": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "quantity": {
                "type": "string"
              },
              "filledQuantity": {
                "type": "string"
              },
              "status": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Null while awaiting signature. Nothing is on the book yet."
              },
              "contractId": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Null until the transaction commits."
              },
              "createdAt": {
                "type": "string",
                "format": "date-time"
              },
              "correlationId": {
                "type": "string"
              },
              "caldenIntentId": {
                "type": "string"
              },
              "providerFeeAmount": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Fee fixed into the transaction awaiting signature. TO BE VERIFIED BEFORE SIGNING. For a fee-exempt account it is \"0\" on every order and every cancel, including when the venue free-traffic allowance is exhausted and when traffic metering is unavailable. A non-zero value means something is wrong: do not sign.",
                "examples": [
                  "0"
                ]
              },
              "providerFeeSymbol": {
                "type": [
                  "string",
                  "null"
                ],
                "examples": [
                  "CC"
                ]
              }
            }
          },
          "signing": {
            "$ref": "#/components/schemas/SigningEnvelope"
          }
        }
      },
      "SubmitRequest": {
        "type": "object",
        "required": [
          "partyId",
          "commandId",
          "signature",
          "publicKey",
          "submitToken",
          "prepared"
        ],
        "properties": {
          "partyId": {
            "type": "string",
            "description": "The Canton party of the market maker."
          },
          "commandId": {
            "type": "string",
            "description": "Verbatim from signing.commandId."
          },
          "signature": {
            "type": "string",
            "description": "Base64 Ed25519 signature over the raw decoded bytes of preparedTransactionHash."
          },
          "publicKey": {
            "type": "string",
            "description": "Base64 public key matching the one registered for the party."
          },
          "submitToken": {
            "type": "string",
            "description": "Verbatim from signing.submitToken."
          },
          "prepared": {
            "type": "object",
            "required": [
              "preparedTransactionHash",
              "hashingSchemeVersion"
            ],
            "properties": {
              "preparedTransactionHash": {
                "type": "string"
              },
              "hashingSchemeVersion": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "responses": {
      "Balances": {
        "description": "Balances per instrument.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "ok",
                "data"
              ],
              "properties": {
                "ok": {
                  "type": "boolean",
                  "const": true
                },
                "data": {
                  "type": "object",
                  "properties": {
                    "partyId": {
                      "type": "string"
                    },
                    "balances": {
                      "type": "array",
                      "description": "Canonical per-instrument list. Amounts are decimal strings. Prefer this over the convenience maps below.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "asset": {
                            "type": "string",
                            "examples": [
                              "CBTC"
                            ]
                          },
                          "available": {
                            "type": "string",
                            "description": "Free to commit to new orders."
                          },
                          "locked": {
                            "type": "string",
                            "description": "Committed to resting orders."
                          }
                        }
                      }
                    },
                    "available": {
                      "type": "object",
                      "description": "Convenience map, asset to amount. JSON numbers: lose precision above 2^53. Compute from `balances`.",
                      "additionalProperties": {
                        "type": "number"
                      }
                    },
                    "locked": {
                      "type": "object",
                      "description": "Convenience map. Same precision caveat.",
                      "additionalProperties": {
                        "type": "number"
                      }
                    },
                    "total": {
                      "type": "object",
                      "description": "available + locked per asset. Same precision caveat.",
                      "additionalProperties": {
                        "type": "number"
                      }
                    },
                    "source": {
                      "type": "string",
                      "examples": [
                        "calden-active-contracts"
                      ]
                    },
                    "asOf": {
                      "type": "object",
                      "properties": {
                        "updateId": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
