{
  "openapi": "3.1.0",
  "info": {
    "title": "Ticky dashboard API",
    "version": "1.0.0",
    "summary": "Accounts, linked Ticky installs and daily habit notes for Ticky, the trading buddy for TradingView.",
    "description": "The API behind Ticky's dashboard and its Chrome extension. It is not a public data API: every call that reads or changes a trader's data needs either the trader's sign-in cookie (set by sign-up or sign-in on this site) or the random install token of their own Ticky extension. There are no API keys. Notes contain counts, dollars, habit results, nudge answers and hours; never symbols, prices or single trades. Writes with the session cookie must come from this site (Origin header checked). Sign-in tries are limited (10 per email and 50 per IP per 15 minutes).\n\n**Versioning.** This is version 1: paths start with /api/v1/ (unversioned /api/ paths are the same version, kept for existing Ticky installs), every response carries `API-Version: 1`, and a request may send `API-Version: 1`; any other value is refused with 400. A breaking change becomes /api/v2/. The old version then keeps working for at least 90 days and announces its end with `Deprecation` (RFC 9745) and `Sunset` (RFC 8594) headers, plus a note in the developer guide.\n\n**Rate limits.** Sign-up and sign-in answer with `RateLimit-Policy` and `RateLimit` headers (draft-ietf-httpapi-ratelimit-headers) and `Retry-After` when a limit is used up (HTTP 429). Other endpoints have no published rate limit.",
    "contact": {
      "name": "Ticky",
      "email": "kabirshah050812@gmail.com",
      "url": "https://ticky-dashboard.gazehop-site.workers.dev/contact"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://ticky-dashboard.gazehop-site.workers.dev"
    }
  ],
  "externalDocs": {
    "description": "Developer guide",
    "url": "https://ticky-dashboard.gazehop-site.workers.dev/developers"
  },
  "tags": [
    {
      "name": "auth",
      "description": "Accounts and sessions"
    },
    {
      "name": "devices",
      "description": "Ticky installs linked to an account"
    },
    {
      "name": "notes",
      "description": "Daily habit notes"
    }
  ],
  "paths": {
    "/api/v1/auth/providers": {
      "get": {
        "operationId": "listSignInProviders",
        "tags": [
          "auth"
        ],
        "summary": "Which sign-in providers are on",
        "description": "Public. Tells whether Google and Microsoft sign-in are switched on.",
        "responses": {
          "200": {
            "description": "Providers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "google": {
                      "type": "boolean"
                    },
                    "microsoft": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "google",
                    "microsoft"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/auth/me": {
      "get": {
        "operationId": "getCurrentUser",
        "tags": [
          "auth"
        ],
        "summary": "The signed-in account",
        "description": "Returns the account for the session cookie, or null when signed out.",
        "security": [
          {},
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "The account, or null",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/User"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "user"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/auth/signup": {
      "post": {
        "operationId": "signUp",
        "tags": [
          "auth"
        ],
        "summary": "Create an account",
        "description": "Creates an account with email and password and sets the session cookie. Must be sent from this site.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 200
                  },
                  "adult": {
                    "type": "boolean",
                    "const": true,
                    "description": "The trader confirms they are 18 or older."
                  }
                },
                "required": [
                  "email",
                  "password",
                  "adult"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed up; Set-Cookie carries the session",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "400": {
            "description": "Invalid email or password, or not 18+",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "403": {
            "description": "Not sent from this site",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "409": {
            "description": "An account with that email exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "429": {
            "description": "Too many tries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/auth/login": {
      "post": {
        "operationId": "signIn",
        "tags": [
          "auth"
        ],
        "summary": "Sign in",
        "description": "Signs in with email and password and sets the session cookie. Must be sent from this site.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string"
                  }
                },
                "required": [
                  "email",
                  "password"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in; Set-Cookie carries the session",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "401": {
            "description": "Email and password don't match",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "403": {
            "description": "Not sent from this site",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "429": {
            "description": "Too many tries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/auth/logout": {
      "post": {
        "operationId": "signOut",
        "tags": [
          "auth"
        ],
        "summary": "Sign out",
        "description": "Ends the session and clears the cookie.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Signed out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/auth/onboarded": {
      "post": {
        "operationId": "finishOnboarding",
        "tags": [
          "auth"
        ],
        "summary": "Mark onboarding done",
        "description": "Records that the account finished onboarding, so it is shown only once.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Done",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/auth/account": {
      "delete": {
        "operationId": "deleteAccount",
        "tags": [
          "auth"
        ],
        "summary": "Delete the account",
        "description": "Deletes the account, its sessions, linked installs and all notes. Cannot be undone.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/auth/oauth/{provider}/start": {
      "get": {
        "operationId": "startProviderSignIn",
        "tags": [
          "auth"
        ],
        "summary": "Start Google or Microsoft sign-in",
        "description": "Browser redirect to the provider (OAuth 2 with PKCE). For people in a browser, not for programs.",
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          },
          {
            "$ref": "#/components/parameters/Provider"
          },
          {
            "name": "next",
            "in": "query",
            "required": false,
            "description": "Where to go after signing in: a path on this site.",
            "schema": {
              "type": "string",
              "enum": [
                "/",
                "/welcome"
              ]
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to the provider's sign-in page",
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/oauth/{provider}/callback": {
      "get": {
        "operationId": "finishProviderSignIn",
        "tags": [
          "auth"
        ],
        "summary": "Return from Google or Microsoft",
        "description": "Where the provider sends the browser back. Sets the session cookie and redirects into the dashboard.",
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          },
          {
            "$ref": "#/components/parameters/Provider"
          },
          {
            "name": "code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect into the dashboard, or back with ?signin=<reason>",
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        }
      }
    },
    "/api/v1/devices": {
      "get": {
        "operationId": "listDevices",
        "tags": [
          "devices"
        ],
        "summary": "List linked installs",
        "description": "The Ticky installs linked to the signed-in account.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Linked installs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "devices": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Device"
                      }
                    }
                  },
                  "required": [
                    "devices"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/devices/{id}": {
      "delete": {
        "operationId": "unlinkDevice",
        "tags": [
          "devices"
        ],
        "summary": "Unlink an install",
        "description": "Unlinks one install from the signed-in account; that Ticky stops working until linked again.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Device id from listDevices.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Unlinked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        }
      }
    },
    "/api/v1/devices/link": {
      "post": {
        "operationId": "linkDevice",
        "tags": [
          "devices"
        ],
        "summary": "Link an install",
        "description": "Links the Ticky install with this token to the signed-in account. The dashboard does this when Ticky in the same Chrome hands over its token.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "install": {
                    "$ref": "#/components/schemas/InstallToken"
                  }
                },
                "required": [
                  "install"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Linked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "linked": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "linked"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "400": {
            "description": "Not an install token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/devices/code": {
      "post": {
        "operationId": "createLinkCode",
        "tags": [
          "devices"
        ],
        "summary": "Get a code to link TradingView Desktop",
        "description": "A one-time 6-digit code, valid for 10 minutes, typed into Ticky in TradingView Desktop.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "The code",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string",
                      "pattern": "^\\d{6}$"
                    }
                  },
                  "required": [
                    "code"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/devices/claim": {
      "post": {
        "operationId": "claimLinkCode",
        "tags": [
          "devices"
        ],
        "summary": "Link an install with a code",
        "description": "Called by Ticky itself: links its install token to the account that created the code.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "install": {
                    "$ref": "#/components/schemas/InstallToken"
                  },
                  "code": {
                    "type": "string",
                    "pattern": "^\\d{6}$"
                  }
                },
                "required": [
                  "install",
                  "code"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Linked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "linked": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "linked"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "400": {
            "description": "Wrong or expired code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/devices/status": {
      "get": {
        "operationId": "getInstallStatus",
        "tags": [
          "devices"
        ],
        "summary": "Is this install linked?",
        "description": "Called by Ticky itself with its install token.",
        "security": [
          {
            "installToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Link status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "linked": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "linked"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "No install token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    },
    "/api/v1/notes": {
      "get": {
        "operationId": "listNotes",
        "tags": [
          "notes"
        ],
        "summary": "The account's daily notes",
        "description": "Every daily note from the account's linked installs, one per day (installs on the same day are added together), oldest first.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Notes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "notes": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DayNote"
                      }
                    }
                  },
                  "required": [
                    "notes"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      },
      "put": {
        "operationId": "putNote",
        "tags": [
          "notes"
        ],
        "summary": "Add or replace a day's note",
        "description": "Called by Ticky itself, only once its install is linked. Sending the same day again replaces it. At most 400 days per install; body at most 4 KB; anything beyond the exact note shape is refused.",
        "security": [
          {
            "installToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DayNote"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "400": {
            "description": "Not a valid note",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "No install token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "403": {
            "description": "Install not linked to an account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "413": {
            "description": "Too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "429": {
            "description": "400 days stored already",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      },
      "delete": {
        "operationId": "deleteNotes",
        "tags": [
          "notes"
        ],
        "summary": "Delete all notes",
        "description": "Deletes every note from the account's linked installs.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiVersion"
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Host-ticky_session",
        "description": "Set by sign-up or sign-in on this site. Secure, HttpOnly, SameSite=Lax; 30 days."
      },
      "installToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "The random 64-hex token of a Ticky extension install, kept in that install's storage."
      }
    },
    "parameters": {
      "Provider": {
        "name": "provider",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "enum": [
            "google",
            "microsoft"
          ]
        }
      },
      "ApiVersion": {
        "name": "API-Version",
        "in": "header",
        "required": false,
        "description": "The API version the caller expects. Only \"1\" is served; anything else gets 400.",
        "schema": {
          "type": "string",
          "enum": [
            "1"
          ],
          "default": "1"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      },
      "User": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "onboarded": {
            "type": "boolean"
          }
        },
        "required": [
          "email",
          "onboarded"
        ]
      },
      "InstallToken": {
        "type": "string",
        "pattern": "^[0-9a-f]{64}$"
      },
      "Device": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string",
            "examples": [
              "Chrome on Mac"
            ]
          },
          "linked_at": {
            "type": "string"
          },
          "last_seen": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "label",
          "linked_at",
          "last_seen"
        ]
      },
      "DayNote": {
        "type": "object",
        "additionalProperties": false,
        "description": "One trading day. Never symbols, prices or single trades.",
        "properties": {
          "day": {
            "type": "string",
            "format": "date"
          },
          "trades": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000,
            "description": "Trades closed that day"
          },
          "wins": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000
          },
          "losses": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000
          },
          "gained": {
            "type": "number",
            "minimum": 0,
            "maximum": 10000000,
            "description": "Dollars gained"
          },
          "lost": {
            "type": "number",
            "minimum": 0,
            "maximum": 10000000,
            "description": "Dollars lost (positive)"
          },
          "habits": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "after_loss": {
                "$ref": "#/components/schemas/HabitResult"
              },
              "size_up": {
                "$ref": "#/components/schemas/HabitResult"
              },
              "size_after_wins": {
                "$ref": "#/components/schemas/HabitResult"
              },
              "add_to_loser": {
                "$ref": "#/components/schemas/HabitResult"
              },
              "cut_winners": {
                "$ref": "#/components/schemas/HabitResult"
              },
              "too_many": {
                "$ref": "#/components/schemas/HabitResult"
              },
              "outside_hours": {
                "$ref": "#/components/schemas/HabitResult"
              },
              "loss_limit": {
                "$ref": "#/components/schemas/HabitResult"
              }
            }
          },
          "nudges": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "break": {
                "type": "integer",
                "minimum": 0
              },
              "keep": {
                "type": "integer",
                "minimum": 0
              },
              "mute": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "break",
              "keep",
              "mute"
            ]
          },
          "hours": {
            "type": "object",
            "description": "Local hour of entry (\"0\"–\"23\") → trades and dollars",
            "propertyNames": {
              "pattern": "^(\\d|1\\d|2[0-3])$"
            },
            "additionalProperties": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "trades": {
                  "type": "integer",
                  "minimum": 0
                },
                "pnl": {
                  "type": "number"
                }
              },
              "required": [
                "trades",
                "pnl"
              ]
            }
          }
        },
        "required": [
          "day",
          "trades",
          "wins",
          "losses",
          "gained",
          "lost",
          "habits",
          "nudges",
          "hours"
        ]
      },
      "HabitResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "fired": {
            "type": "integer",
            "minimum": 0,
            "description": "Times the habit happened"
          },
          "pnl": {
            "type": "number",
            "description": "Dollars those trades made or lost"
          }
        },
        "required": [
          "fired",
          "pnl"
        ]
      }
    },
    "headers": {
      "API-Version": {
        "description": "The API version that answered.",
        "schema": {
          "type": "string",
          "const": "1"
        }
      },
      "RateLimit-Policy": {
        "description": "The limits that apply, e.g. \"email\";q=10;w=900, \"ip\";q=50;w=900 (q tries per w seconds).",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit": {
        "description": "What is left of each limit and when it resets, e.g. \"email\";r=7;t=812.",
        "schema": {
          "type": "string"
        }
      },
      "Retry-After": {
        "description": "Seconds until a used-up limit resets (with 429).",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      }
    }
  },
  "x-api-version": "1"
}