{
  "openapi": "3.1.1",
  "info": {
    "title": "Easy API Trade: HTTP API",
    "description": "Easy API Trade is a trading simulator. All money is play money: nothing here places an order on a real market. With an API key you can deposit play money, read live quotes, buy and sell, and read your positions and orders. An order fills at once and in full at the latest quote; there is no order book and no short selling. Limits such as the daily deposit cap and the orders allowed per minute are reported by the errors that enforce them.\n\nQuotes also stream over a WebSocket at /stream/v1/ws, which takes the same X-API-Key header. Messages are JSON text. Send {\"op\":\"subscribe\",\"symbols\":[\"SPY\"]} (or \"*\" for every symbol) to receive {\"type\":\"quote\",\"symbol\":...,\"price\":...,\"volume\":...,\"trade_ts\":...,\"ts\":...} messages, at most one per symbol per second. Send {\"op\":\"order\",\"id\":\"1\",\"symbol\":\"SPY\",\"side\":\"buy\",\"amount\":25} to trade, with the same fields as POST /orders plus an id of your choice; the reply is {\"type\":\"order\",\"id\":\"1\",\"order\":{...}} or {\"type\":\"error\",\"id\":\"1\",\"code\":...,\"message\":...}.",
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://easyapitrade.com/"
    }
  ],
  "paths": {
    "/api/v1/instruments": {
      "get": {
        "tags": [
          "Market data"
        ],
        "summary": "List the tradable symbols.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InstrumentDto"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Any error, for example 401 without a valid key, 422 when an order cannot be filled, 429 when a limit is reached.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "status",
                    "code",
                    "detail"
                  ],
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code."
                    },
                    "code": {
                      "type": "string",
                      "description": "A stable name for the error, for programs to act on. For example: unauthorized, invalid_request, unknown_symbol, market_closed, insufficient_funds, insufficient_position, deposit_limit_exceeded, order_limit_exceeded, rate_limited."
                    },
                    "detail": {
                      "type": "string",
                      "description": "What went wrong, in a sentence for a person."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/quotes": {
      "get": {
        "tags": [
          "Market data"
        ],
        "summary": "Get the latest quote for every symbol.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/QuoteDto"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Any error, for example 401 without a valid key, 422 when an order cannot be filled, 429 when a limit is reached.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "status",
                    "code",
                    "detail"
                  ],
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code."
                    },
                    "code": {
                      "type": "string",
                      "description": "A stable name for the error, for programs to act on. For example: unauthorized, invalid_request, unknown_symbol, market_closed, insufficient_funds, insufficient_position, deposit_limit_exceeded, order_limit_exceeded, rate_limited."
                    },
                    "detail": {
                      "type": "string",
                      "description": "What went wrong, in a sentence for a person."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/quotes/{symbol}": {
      "get": {
        "tags": [
          "Market data"
        ],
        "summary": "Get the latest quote for one symbol.",
        "parameters": [
          {
            "name": "symbol",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteDto"
                }
              }
            }
          },
          "default": {
            "description": "Any error, for example 401 without a valid key, 422 when an order cannot be filled, 429 when a limit is reached.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "status",
                    "code",
                    "detail"
                  ],
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code."
                    },
                    "code": {
                      "type": "string",
                      "description": "A stable name for the error, for programs to act on. For example: unauthorized, invalid_request, unknown_symbol, market_closed, insufficient_funds, insufficient_position, deposit_limit_exceeded, order_limit_exceeded, rate_limited."
                    },
                    "detail": {
                      "type": "string",
                      "description": "What went wrong, in a sentence for a person."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/account": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get the cash balance and what is left of today's deposit allowance.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountSummary"
                }
              }
            }
          },
          "default": {
            "description": "Any error, for example 401 without a valid key, 422 when an order cannot be filled, 429 when a limit is reached.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "status",
                    "code",
                    "detail"
                  ],
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code."
                    },
                    "code": {
                      "type": "string",
                      "description": "A stable name for the error, for programs to act on. For example: unauthorized, invalid_request, unknown_symbol, market_closed, insufficient_funds, insufficient_position, deposit_limit_exceeded, order_limit_exceeded, rate_limited."
                    },
                    "detail": {
                      "type": "string",
                      "description": "What went wrong, in a sentence for a person."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/deposits": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Deposit play money. Returns the account as it is afterwards.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountSummary"
                }
              }
            }
          },
          "default": {
            "description": "Any error, for example 401 without a valid key, 422 when an order cannot be filled, 429 when a limit is reached.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "status",
                    "code",
                    "detail"
                  ],
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code."
                    },
                    "code": {
                      "type": "string",
                      "description": "A stable name for the error, for programs to act on. For example: unauthorized, invalid_request, unknown_symbol, market_closed, insufficient_funds, insufficient_position, deposit_limit_exceeded, order_limit_exceeded, rate_limited."
                    },
                    "detail": {
                      "type": "string",
                      "description": "What went wrong, in a sentence for a person."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/positions": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "List the holdings, each with its value and gain or loss at the latest price.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PositionView"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Any error, for example 401 without a valid key, 422 when an order cannot be filled, 429 when a limit is reached.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "status",
                    "code",
                    "detail"
                  ],
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code."
                    },
                    "code": {
                      "type": "string",
                      "description": "A stable name for the error, for programs to act on. For example: unauthorized, invalid_request, unknown_symbol, market_closed, insufficient_funds, insufficient_position, deposit_limit_exceeded, order_limit_exceeded, rate_limited."
                    },
                    "detail": {
                      "type": "string",
                      "description": "What went wrong, in a sentence for a person."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/orders": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Buy or sell. The order fills at once, in full, at the latest quote.",
        "description": "Size the order with exactly one of quantity, amount or all; none, or more than one, is refused with invalid_request. Nothing is ever queued: an order fills in full or is refused. A symbol whose quote is not open is refused with market_closed.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "default": {
            "description": "Any error, for example 401 without a valid key, 422 when an order cannot be filled, 429 when a limit is reached.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "status",
                    "code",
                    "detail"
                  ],
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code."
                    },
                    "code": {
                      "type": "string",
                      "description": "A stable name for the error, for programs to act on. For example: unauthorized, invalid_request, unknown_symbol, market_closed, insufficient_funds, insufficient_position, deposit_limit_exceeded, order_limit_exceeded, rate_limited."
                    },
                    "detail": {
                      "type": "string",
                      "description": "What went wrong, in a sentence for a person."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Orders"
        ],
        "summary": "List past orders, newest first.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "How many orders to return, from 1 to 200.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Return orders older than the order with this id. Pass the id of the last order of a page to get the next page.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Order"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Any error, for example 401 without a valid key, 422 when an order cannot be filled, 429 when a limit is reached.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "status",
                    "code",
                    "detail"
                  ],
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code."
                    },
                    "code": {
                      "type": "string",
                      "description": "A stable name for the error, for programs to act on. For example: unauthorized, invalid_request, unknown_symbol, market_closed, insufficient_funds, insufficient_position, deposit_limit_exceeded, order_limit_exceeded, rate_limited."
                    },
                    "detail": {
                      "type": "string",
                      "description": "What went wrong, in a sentence for a person."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/orders/{id}": {
      "get": {
        "tags": [
          "Orders"
        ],
        "summary": "Get one order.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "default": {
            "description": "Any error, for example 401 without a valid key, 422 when an order cannot be filled, 429 when a limit is reached.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "status",
                    "code",
                    "detail"
                  ],
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code."
                    },
                    "code": {
                      "type": "string",
                      "description": "A stable name for the error, for programs to act on. For example: unauthorized, invalid_request, unknown_symbol, market_closed, insufficient_funds, insufficient_position, deposit_limit_exceeded, order_limit_exceeded, rate_limited."
                    },
                    "detail": {
                      "type": "string",
                      "description": "What went wrong, in a sentence for a person."
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AccountSummary": {
        "required": [
          "account_id",
          "cash_balance",
          "daily_deposit_limit",
          "deposited_today",
          "deposit_remaining_today"
        ],
        "type": "object",
        "properties": {
          "account_id": {
            "type": "string",
            "format": "uuid"
          },
          "cash_balance": {
            "type": "number",
            "description": "Play money available to buy with."
          },
          "daily_deposit_limit": {
            "type": "number",
            "description": "Most that can be deposited per UTC day."
          },
          "deposited_today": {
            "type": "number"
          },
          "deposit_remaining_today": {
            "type": "number",
            "description": "How much more can be deposited today."
          }
        }
      },
      "DepositDto": {
        "required": [
          "amount"
        ],
        "type": "object",
        "properties": {
          "amount": {
            "type": [
              "null",
              "number"
            ],
            "description": "Dollars of play money to add, with up to 2 decimal places."
          }
        }
      },
      "InstrumentDto": {
        "required": [
          "symbol",
          "name",
          "kind"
        ],
        "type": "object",
        "properties": {
          "symbol": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "enum": [
              "equity",
              "crypto"
            ],
            "type": "string"
          }
        }
      },
      "Order": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "account_id": {
            "type": "string",
            "format": "uuid"
          },
          "symbol": {
            "type": "string"
          },
          "side": {
            "enum": [
              "buy",
              "sell"
            ],
            "type": "string"
          },
          "requested_quantity": {
            "type": [
              "null",
              "number"
            ],
            "description": "The quantity asked for, when the order was sized by quantity."
          },
          "requested_amount": {
            "type": [
              "null",
              "number"
            ],
            "description": "The dollar amount asked for, when the order was sized by amount."
          },
          "requested_all": {
            "type": "boolean",
            "description": "True when the order asked to sell the whole holding."
          },
          "quantity": {
            "type": "number",
            "description": "Units bought or sold."
          },
          "price": {
            "type": "number",
            "description": "Price per unit the order filled at."
          },
          "notional": {
            "type": "number",
            "description": "Cash paid (buy) or received (sell)."
          },
          "realized_pnl": {
            "type": [
              "null",
              "number"
            ],
            "description": "Gain or loss a sell locked in against the average cost. Absent on buys."
          },
          "client_order_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "The id the client sent with the order, if any."
          },
          "quote_ts": {
            "type": "integer",
            "description": "Publish time of the quote the order filled at, in Unix milliseconds.",
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OrderDto": {
        "required": [
          "symbol",
          "side"
        ],
        "type": "object",
        "properties": {
          "symbol": {
            "type": [
              "null",
              "string"
            ],
            "description": "The symbol to trade, for example \"SPY\"."
          },
          "side": {
            "enum": [
              "buy",
              "sell"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Lower case is conventional; case is ignored."
          },
          "quantity": {
            "type": [
              "null",
              "number"
            ],
            "description": "Size the order in units, with up to 8 decimal places. Give exactly one of quantity, amount or all."
          },
          "amount": {
            "type": [
              "null",
              "number"
            ],
            "description": "Size the order in dollars: to spend (buy) or to receive (sell). Give exactly one of quantity, amount or all."
          },
          "all": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "True sells the whole holding. Sells only. Give exactly one of quantity, amount or all."
          },
          "client_order_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional id of your choice, up to 64 characters. Sending the same id again returns the original order instead of placing another."
          }
        }
      },
      "PositionView": {
        "required": [
          "symbol",
          "quantity",
          "average_cost"
        ],
        "type": "object",
        "properties": {
          "symbol": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "average_cost": {
            "type": "number",
            "description": "Average price paid per unit held."
          },
          "price": {
            "type": [
              "null",
              "number"
            ],
            "description": "Latest price. Absent when there is no quote."
          },
          "market_value": {
            "type": [
              "null",
              "number"
            ],
            "description": "What the holding would sell for now. Absent when there is no quote."
          },
          "unrealized_pnl": {
            "type": [
              "null",
              "number"
            ],
            "description": "Market value minus what the holding cost. Absent when there is no quote."
          }
        }
      },
      "QuoteDto": {
        "required": [
          "symbol",
          "price",
          "volume",
          "trade_ts",
          "ts",
          "open"
        ],
        "type": "object",
        "properties": {
          "symbol": {
            "type": "string"
          },
          "price": {
            "type": "number",
            "description": "Price of the last trade."
          },
          "volume": {
            "type": "number",
            "description": "Volume traded since the previous quote."
          },
          "trade_ts": {
            "type": "integer",
            "description": "Time of the last trade, in Unix milliseconds.",
            "format": "int64"
          },
          "ts": {
            "type": "integer",
            "description": "Time the quote was published, in Unix milliseconds.",
            "format": "int64"
          },
          "open": {
            "type": "boolean",
            "description": "Whether the symbol can be traded now. False when its quotes have stopped."
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "description": "Your API key, on every request. Each key is its own trading account. \"Authorization: Bearer <key>\" works too.",
        "name": "X-API-Key",
        "in": "header"
      }
    }
  },
  "security": [
    {
      "ApiKey": [ ]
    }
  ],
  "tags": [
    {
      "name": "Market data"
    },
    {
      "name": "Account"
    },
    {
      "name": "Orders"
    }
  ]
}