> ## Documentation Index
> Fetch the complete documentation index at: https://finance.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Chart Configuration

> Retrieves the chart configuration metadata including supported time resolutions, intraday multipliers, and data capabilities. This endpoint provides essential information for initializing charting libraries and understanding available data granularity options.

**Use Case:** Configure trading chart applications with supported timeframes and resolution settings before requesting historical data.


export default function OAuthLoginButton({scopes = "user:information account:information order:execution order:information position:information market:information calendar:information options:information analytics:information market:supplemental", responseType = "token", buttonText = "Authenticate with OAuth", showStatus = true}) {
  const [isDarkMode, setIsDarkMode] = useState(false);
  useEffect(() => {
    const checkDarkMode = () => {
      const isDark = document.documentElement.classList.contains("dark") || document.documentElement.getAttribute("data-theme") === "dark" || document.body.classList.contains("dark") || document.body.getAttribute("data-theme") === "dark";
      setIsDarkMode(isDark);
    };
    checkDarkMode();
    const htmlObserver = new MutationObserver(checkDarkMode);
    const bodyObserver = new MutationObserver(checkDarkMode);
    htmlObserver.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class", "data-theme", "style"]
    });
    bodyObserver.observe(document.body, {
      attributes: true,
      attributeFilter: ["class", "data-theme", "style"]
    });
    const interval = setInterval(checkDarkMode, 1000);
    return () => {
      htmlObserver.disconnect();
      bodyObserver.disconnect();
      clearInterval(interval);
    };
  }, []);
  const styles = useMemo(() => ({
    statusContainer: {
      marginBottom: "1.5rem",
      padding: "0.875rem 1rem",
      backgroundColor: isDarkMode ? "rgba(11, 170, 94, 0.08)" : "rgba(11, 170, 94, 0.06)",
      border: isDarkMode ? "1px solid rgba(11, 170, 94, 0.25)" : "1px solid rgba(11, 170, 94, 0.25)",
      borderRadius: "10px"
    },
    statusContent: {
      display: "flex",
      alignItems: "center",
      justifyContent: "space-between",
      gap: "1rem",
      flexWrap: "wrap"
    },
    statusLeft: {
      display: "flex",
      alignItems: "center",
      gap: "1rem",
      flexWrap: "wrap"
    },
    statusBadge: {
      display: "flex",
      alignItems: "center",
      gap: "0.5rem"
    },
    checkmark: {
      color: isDarkMode ? "#0BAA5E" : "#0BAA5E",
      fontSize: "1.25rem",
      fontWeight: "bold"
    },
    statusText: {
      color: isDarkMode ? "#0BAA5E" : "#0BAA5E",
      fontWeight: "600",
      fontSize: "0.95rem"
    },
    expiryText: {
      color: isDarkMode ? "#a1a1aa" : "#71717a",
      fontSize: "0.8125rem"
    },
    logoutButton: {
      padding: "0.375rem 0.75rem",
      backgroundColor: "transparent",
      color: isDarkMode ? "#e4e4e7" : "#3f3f46",
      border: isDarkMode ? "1px solid rgba(255, 255, 255, 0.1)" : "1px solid rgba(0, 0, 0, 0.1)",
      borderRadius: "6px",
      cursor: "pointer",
      fontSize: "0.8125rem",
      fontWeight: "500",
      transition: "background-color 0.15s ease"
    },
    logoutButtonHover: {
      backgroundColor: isDarkMode ? "rgba(255, 255, 255, 0.05)" : "rgba(0, 0, 0, 0.04)"
    },
    buttonContainer: {
      marginBottom: "1.5rem",
      display: "flex",
      alignItems: "center",
      justifyContent: "space-between",
      gap: "1rem",
      padding: "0.875rem 1rem",
      backgroundColor: "transparent",
      border: isDarkMode ? "1px solid rgba(255, 255, 255, 0.1)" : "1px solid rgba(0, 0, 0, 0.08)",
      borderRadius: "10px"
    },
    loginButton: {
      display: "inline-flex",
      alignItems: "center",
      gap: "0.5rem",
      padding: "0.5rem 0.875rem",
      backgroundColor: "#0BAA5E",
      color: "white",
      border: "1px solid #0BAA5E",
      borderRadius: "8px",
      cursor: "pointer",
      fontSize: "0.8125rem",
      fontWeight: "500",
      lineHeight: "1.25rem",
      transition: "background-color 0.15s ease, border-color 0.15s ease",
      whiteSpace: "nowrap",
      flexShrink: 0
    },
    loginButtonHover: {
      backgroundColor: "#098F4E",
      borderColor: "#098F4E"
    },
    lockIcon: {
      width: "14px",
      height: "14px",
      flexShrink: 0
    },
    helpText: {
      margin: 0,
      fontSize: "0.8125rem",
      color: isDarkMode ? "#9ca3af" : "#6b7280",
      lineHeight: "1.5",
      flex: 1
    },
    modalDialog: {
      border: "none",
      backgroundColor: "transparent",
      padding: 0,
      margin: 0,
      maxWidth: "100%",
      maxHeight: "100%"
    },
    modalContent: {
      backgroundColor: isDarkMode ? "#0f0f10" : "#ffffff",
      border: isDarkMode ? "1px solid rgba(255, 255, 255, 0.08)" : "1px solid rgba(0, 0, 0, 0.08)",
      borderRadius: "12px",
      padding: "1.5rem",
      maxWidth: "500px",
      width: "100%",
      boxShadow: isDarkMode ? "0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.3)" : "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
    },
    modalHeader: {
      display: "flex",
      justifyContent: "space-between",
      alignItems: "center",
      marginBottom: "1.5rem"
    },
    modalTitle: {
      margin: 0,
      fontSize: "1.125rem",
      fontWeight: "600",
      color: isDarkMode ? "#fafafa" : "#0a0a0a"
    },
    closeButton: {
      background: "none",
      border: "none",
      fontSize: "1.5rem",
      lineHeight: 1,
      color: isDarkMode ? "#a1a1aa" : "#71717a",
      cursor: "pointer",
      padding: "0",
      width: "2rem",
      height: "2rem",
      display: "flex",
      alignItems: "center",
      justifyContent: "center",
      borderRadius: "6px",
      transition: "color 0.15s ease, background-color 0.15s ease"
    },
    form: {
      display: "flex",
      flexDirection: "column",
      gap: "1rem"
    },
    formGroup: {
      display: "flex",
      flexDirection: "column",
      gap: "0.5rem"
    },
    label: {
      fontSize: "0.8125rem",
      fontWeight: "500",
      color: isDarkMode ? "#e4e4e7" : "#3f3f46"
    },
    input: {
      padding: "0.5rem 0.75rem",
      border: isDarkMode ? "1px solid rgba(255, 255, 255, 0.1)" : "1px solid rgba(0, 0, 0, 0.1)",
      borderRadius: "8px",
      fontSize: "0.875rem",
      color: isDarkMode ? "#fafafa" : "#0a0a0a",
      backgroundColor: isDarkMode ? "rgba(255, 255, 255, 0.03)" : "#ffffff",
      transition: "border-color 0.15s ease, box-shadow 0.15s ease",
      outline: "none"
    },
    inputHelp: {
      margin: 0,
      fontSize: "0.75rem",
      color: isDarkMode ? "#a1a1aa" : "#71717a"
    },
    link: {
      color: "#0BAA5E",
      textDecoration: "none",
      fontWeight: "500"
    },
    errorBox: {
      padding: "0.75rem",
      backgroundColor: isDarkMode ? "rgba(220, 38, 38, 0.1)" : "rgba(220, 38, 38, 0.05)",
      border: isDarkMode ? "1px solid rgba(220, 38, 38, 0.3)" : "1px solid rgba(220, 38, 38, 0.2)",
      borderRadius: "8px",
      color: isDarkMode ? "#fca5a5" : "#dc2626",
      fontSize: "0.8125rem"
    },
    modalFooter: {
      display: "flex",
      gap: "0.5rem",
      justifyContent: "flex-end",
      marginTop: "0.5rem"
    },
    cancelButton: {
      padding: "0.5rem 0.875rem",
      backgroundColor: "transparent",
      color: isDarkMode ? "#e4e4e7" : "#3f3f46",
      border: isDarkMode ? "1px solid rgba(255, 255, 255, 0.1)" : "1px solid rgba(0, 0, 0, 0.1)",
      borderRadius: "8px",
      cursor: "pointer",
      fontSize: "0.8125rem",
      fontWeight: "500",
      lineHeight: "1.25rem",
      transition: "background-color 0.15s ease"
    },
    submitButton: {
      padding: "0.5rem 0.875rem",
      backgroundColor: "#0BAA5E",
      color: "white",
      border: "1px solid #0BAA5E",
      borderRadius: "8px",
      cursor: "pointer",
      fontSize: "0.8125rem",
      fontWeight: "500",
      lineHeight: "1.25rem",
      transition: "background-color 0.15s ease, border-color 0.15s ease"
    },
    submitButtonDisabled: {
      opacity: 0.6,
      cursor: "not-allowed"
    },
    redirectUrlContainer: {
      display: "flex",
      alignItems: "center",
      gap: "0.5rem",
      padding: "0.5rem 0.75rem",
      backgroundColor: isDarkMode ? "rgba(255, 255, 255, 0.03)" : "rgba(0, 0, 0, 0.03)",
      border: isDarkMode ? "1px solid rgba(255, 255, 255, 0.08)" : "1px solid rgba(0, 0, 0, 0.08)",
      borderRadius: "8px",
      fontSize: "0.8125rem",
      fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace"
    },
    redirectUrlText: {
      flex: 1,
      color: isDarkMode ? "#a1a1aa" : "#71717a",
      overflow: "hidden",
      textOverflow: "ellipsis",
      whiteSpace: "nowrap"
    },
    copyButton: {
      padding: "0.25rem 0.625rem",
      backgroundColor: "transparent",
      color: isDarkMode ? "#e4e4e7" : "#3f3f46",
      border: isDarkMode ? "1px solid rgba(255, 255, 255, 0.1)" : "1px solid rgba(0, 0, 0, 0.1)",
      borderRadius: "6px",
      cursor: "pointer",
      fontSize: "0.75rem",
      fontWeight: "500",
      transition: "background-color 0.15s ease, border-color 0.15s ease",
      whiteSpace: "nowrap"
    },
    copyButtonHover: {
      backgroundColor: isDarkMode ? "rgba(255, 255, 255, 0.05)" : "rgba(0, 0, 0, 0.04)"
    },
    copyButtonCopied: {
      backgroundColor: "#0BAA5E",
      color: "white",
      border: "1px solid #0BAA5E"
    }
  }), [isDarkMode]);
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [clientId, setClientId] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [hasValidToken, setHasValidToken] = useState(false);
  const [tokenSource, setTokenSource] = useState(null);
  const [timeRemaining, setTimeRemaining] = useState(0);
  const [error, setError] = useState("");
  const [copied, setCopied] = useState(false);
  const redirectUrl = typeof window !== "undefined" ? window.location.origin + "/api-reference" : "";
  useEffect(() => {
    updateTokenState();
    if (window.AriesOAuth) {
      const lastClientId = window.AriesOAuth.getLastClientId();
      setClientId(lastClientId);
    }
    const handleTokenUpdate = () => {
      updateTokenState();
    };
    const handleOAuthError = event => {
      setError(event.detail.description || "Authentication failed");
      setIsLoading(false);
    };
    const handleOAuthSuccess = () => {
      setIsModalOpen(false);
      setIsLoading(false);
      setError("");
    };
    window.addEventListener("tokenStatusChanged", handleTokenUpdate);
    window.addEventListener("tokenUpdated", handleTokenUpdate);
    window.addEventListener("tokenCleared", handleTokenUpdate);
    window.addEventListener("oauthError", handleOAuthError);
    window.addEventListener("oauthSuccess", handleOAuthSuccess);
    const interval = setInterval(() => {
      if (hasValidToken) {
        updateTokenState();
      }
    }, 1000);
    return () => {
      window.removeEventListener("tokenStatusChanged", handleTokenUpdate);
      window.removeEventListener("tokenUpdated", handleTokenUpdate);
      window.removeEventListener("tokenCleared", handleTokenUpdate);
      window.removeEventListener("oauthError", handleOAuthError);
      window.removeEventListener("oauthSuccess", handleOAuthSuccess);
      clearInterval(interval);
    };
  }, [hasValidToken]);
  const updateTokenState = useCallback(() => {
    if (window.AriesOAuth) {
      const isValid = window.AriesOAuth.isAuthenticated();
      const remaining = window.AriesOAuth.getTimeRemaining();
      const knownExpiry = window.AriesOAuth.hasKnownExpiry ? window.AriesOAuth.hasKnownExpiry() : false;
      const source = window.AriesOAuth.getTokenSource ? window.AriesOAuth.getTokenSource() : null;
      setHasValidToken(isValid);
      setTokenSource(source);
      setTimeRemaining(knownExpiry && typeof remaining === "number" ? remaining : null);
    }
  }, []);
  const handleLogin = () => {
    setError("");
    setIsModalOpen(true);
  };
  const handleLogout = () => {
    if (window.AriesOAuth) {
      window.AriesOAuth.logout();
    }
    try {
      const cfg = window.AriesOAuth?.config;
      const tokenKey = cfg?.TOKEN_KEY ?? "aries_access_token";
      const expiryKey = cfg?.TOKEN_EXPIRY_KEY ?? "aries_token_timestamp";
      const sourceKey = cfg?.TOKEN_SOURCE_KEY ?? "aries_token_source";
      localStorage.removeItem(tokenKey);
      localStorage.removeItem(expiryKey);
      localStorage.removeItem(sourceKey);
    } catch (_) {}
    setHasValidToken(false);
    setTimeRemaining(null);
  };
  const handleOAuthRedirect = async e => {
    e.preventDefault();
    if (!clientId.trim()) {
      setError("Please enter your Client ID");
      return;
    }
    setIsLoading(true);
    try {
      if (window.AriesOAuth) {
        window.AriesOAuth.saveClientId(clientId.trim());
      }
      const returnPath = window.location.pathname + window.location.search + window.location.hash;
      sessionStorage.setItem("oauth_return_path", returnPath);
      const pkce = await window.AriesOAuth.generatePKCE();
      const authEndpoint = window.AriesOAuth?.config?.AUTH_ENDPOINT || "https://app.aries.com/oauth2/authorize";
      const authUrl = new URL(authEndpoint);
      authUrl.searchParams.set("client_id", clientId.trim());
      authUrl.searchParams.set("redirect_uri", redirectUrl);
      authUrl.searchParams.set("response_type", "code");
      authUrl.searchParams.set("code_challenge", pkce.challenge);
      authUrl.searchParams.set("code_challenge_method", "S256");
      authUrl.searchParams.set("scope", scopes);
      authUrl.searchParams.set("state", generateState());
      const fullAuthUrl = authUrl.toString();
      setTimeout(() => {
        window.location.href = fullAuthUrl;
      }, 100);
    } catch (error) {
      setError("Failed to initiate OAuth flow: " + error.message);
      setIsLoading(false);
    }
  };
  const generateState = () => {
    return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
  };
  const formatTimeRemaining = seconds => {
    const minutes = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${minutes}m ${secs}s`;
  };
  const copyRedirectUrl = () => {
    navigator.clipboard.writeText(redirectUrl).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    }).catch(() => {});
  };
  const oauthDialogRef = useRef(null);
  const isLoadingRef = useRef(false);
  isLoadingRef.current = isLoading;
  const closeModal = useCallback(() => {
    if (!isLoading) {
      setIsModalOpen(false);
      setError("");
      setCopied(false);
    }
  }, [isLoading]);
  useEffect(() => {
    const el = oauthDialogRef.current;
    if (!el) return;
    if (isModalOpen) {
      if (!el.open) el.showModal();
    } else {
      if (el.open) el.close();
    }
  }, [isModalOpen]);
  useEffect(() => {
    const el = oauthDialogRef.current;
    if (!el) return;
    const onClose = () => {
      setIsModalOpen(false);
      setError("");
      setCopied(false);
    };
    const onCancel = e => {
      if (isLoadingRef.current) e.preventDefault();
    };
    el.addEventListener("close", onClose);
    el.addEventListener("cancel", onCancel);
    return () => {
      el.removeEventListener("close", onClose);
      el.removeEventListener("cancel", onCancel);
    };
  }, [hasValidToken, showStatus]);
  if (hasValidToken && showStatus && tokenSource === "oauth") {
    return <div style={styles.statusContainer}>
        <div style={styles.statusContent}>
          <div style={styles.statusLeft}>
            <div style={styles.statusBadge}>
              <span style={styles.checkmark}>✓</span>
              <span style={styles.statusText}>Authenticated</span>
            </div>
            {typeof timeRemaining === "number" ? <span style={styles.expiryText}>
                Expires in {formatTimeRemaining(timeRemaining)}
              </span> : null}
          </div>
          <button onClick={handleLogout} style={styles.logoutButton} onMouseEnter={e => e.target.style.backgroundColor = styles.logoutButtonHover.backgroundColor} onMouseLeave={e => e.target.style.backgroundColor = styles.logoutButton.backgroundColor}>
            Logout
          </button>
        </div>
      </div>;
  }
  const onDialogClick = e => {
    if (e.target === e.currentTarget) {
      closeModal();
    }
  };
  const modalMarkup = <dialog ref={oauthDialogRef} className="aries-oauth-dialog" data-oauth-theme={isDarkMode ? "dark" : "light"} style={styles.modalDialog} onClick={onDialogClick}>
      <div style={styles.modalContent} onClick={e => e.stopPropagation()}>
        <div style={styles.modalHeader}>
          <h3 style={styles.modalTitle}>OAuth Authentication</h3>
          <button type="button" onClick={closeModal} style={styles.closeButton} disabled={isLoading}>
            ×
          </button>
        </div>

        <form onSubmit={handleOAuthRedirect} style={styles.form}>
          <div style={styles.formGroup}>
            <label htmlFor="clientId" style={styles.label}>
              Client ID
            </label>
            <input id="clientId" type="text" value={clientId} onChange={e => setClientId(e.target.value)} placeholder="Enter your OAuth Client ID" style={styles.input} disabled={isLoading} />
            <p style={styles.inputHelp}>
              Get your Client ID from{" "}
              <a href="https://app.aries.com/client-center/api" target="_blank" rel="noopener noreferrer" style={styles.link}>
                Client Center / Manage Account → API
              </a>
            </p>
          </div>

          <div style={styles.formGroup}>
            <label style={styles.label}>Redirect URL</label>
            <div style={styles.redirectUrlContainer}>
              <span style={styles.redirectUrlText} title={redirectUrl}>
                {redirectUrl}
              </span>
              <button type="button" onClick={copyRedirectUrl} style={{
    ...styles.copyButton,
    ...copied ? styles.copyButtonCopied : {}
  }} onMouseEnter={e => {
    if (!copied) {
      e.currentTarget.style.backgroundColor = styles.copyButtonHover.backgroundColor;
    }
  }} onMouseLeave={e => {
    if (!copied) {
      e.currentTarget.style.backgroundColor = styles.copyButton.backgroundColor;
    }
  }}>
                {copied ? "✓ Copied" : "Copy"}
              </button>
            </div>
            <p style={styles.inputHelp}>
              Add this URL to your OAuth client's allowed redirect URIs
            </p>
          </div>

          {error && <div style={styles.errorBox}>{error}</div>}

          <div style={styles.modalFooter}>
            <button type="button" onClick={closeModal} style={styles.cancelButton} disabled={isLoading}>
              Cancel
            </button>
            <button type="submit" style={{
    ...styles.submitButton,
    ...isLoading ? styles.submitButtonDisabled : {}
  }} disabled={isLoading}>
              {isLoading ? "Redirecting..." : "Initiate Login"}
            </button>
          </div>
        </form>
      </div>
    </dialog>;
  return <>
      {}
      <div style={styles.buttonContainer}>
        <div style={styles.helpText}>
          <strong style={{
    color: isDarkMode ? "#e5e7eb" : "#374151"
  }}>
            Quick Auth:
          </strong>{" "}
          Authenticate once to auto-fill your Bearer token across all API
          endpoints
        </div>
        <button onClick={handleLogin} style={styles.loginButton} onMouseEnter={e => {
    e.currentTarget.style.backgroundColor = styles.loginButtonHover.backgroundColor;
    e.currentTarget.style.borderColor = styles.loginButtonHover.borderColor;
  }} onMouseLeave={e => {
    e.currentTarget.style.backgroundColor = styles.loginButton.backgroundColor;
    e.currentTarget.style.borderColor = styles.loginButton.borderColor;
  }}>
          <svg style={styles.lockIcon} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
            <path d="M7 11V7a5 5 0 0 1 10 0v4" />
          </svg>
          {buttonText}
        </button>
      </div>

      {modalMarkup}
    </>;
}

<OAuthLoginButton />


## OpenAPI

````yaml openapi.json GET /v1/chart/config
openapi: 3.0.3
info:
  contact:
    email: dev@aries.com
    name: Aries Financial
  description: >-
    OpenAPI Specification for the Aries trading platform API.


    # Authentication


    Learn how to authenticate with the Aries API using OAuth2 and manage access
    tokens in your SDK.


    ## Overview


    The Aries API uses **OAuth2 with Bearer tokens** (JWT format) for
    authentication. All API requests require a valid access token in the
    `Authorization` header:


    ```

    Authorization: Bearer <access_token>

    ```


    ## Providing Client ID and Client Secret (SDK)


    When using the generated SDK, provide your **Client ID** and **Client
    Secret** when you create the API client (e.g. in the constructor or security
    options). The SDK will use these to obtain and refresh the access token
    internally; you do not need to manage tokens yourself.


    Obtain your OAuth2 credentials from the Aries platform (e.g. Client Center /
    Manage Account at https://app.aries.com):


    - **Client ID** – Your application identifier (pass to SDK client)

    - **Client Secret** – Your application secret key (pass to SDK client; use
    PKCE for public clients where secret cannot be stored)


    ## Authentication Flow


    ### 1. Authorization Code Flow


    For server-side or confidential clients:


    1. **Redirect the user** to the authorization URL to sign in and consent:
     - **URL:** `https://app.aries.com/oauth2/authorize`
     - **Query params:** `response_type=code`, `client_id`, `redirect_uri`, `scope`, `state`

    2. **Exchange the code for tokens** (after user is redirected back with
    `?code=.`):
     - **POST** `https://api.aries.com/v1/oauth2/token`
     - **Body:** `grant_type=authorization_code`, `code`, `redirect_uri`, `client_id`, `client_secret`
     - Response includes `access_token` and `refresh_token`

    3. **Call the API** with the access token: `Authorization: Bearer
    <access_token>`


    ### 2. PKCE Flow


    For SPAs and mobile apps (public clients that cannot store `client_secret`):


    1. Generate a **code_verifier** (random string) and **code_challenge** =
    BASE64URL(SHA256(code_verifier)).

    2. **Redirect the user** to `https://app.aries.com/oauth2/authorize` with
    `code_challenge`, `code_challenge_method=S256`, plus `client_id`,
    `redirect_uri`, `scope`, `state`.

    3. **Exchange the code** at POST `https://api.aries.com/v1/oauth2/token`
    with `grant_type=authorization_code`, `code`, `redirect_uri`, `client_id`,
    `code_verifier` (no client_secret).

    4. Use the returned `access_token` as Bearer.


    ### 3. MFA Verification


    If the user has MFA enabled, the authorize step may return `is_mfa: true`
    and a `next_step_auth_id`. Call **POST**
    `https://api.aries.com/v1/oauth2/authorize/mfa` with `next_step_auth_id` and
    `verification_code` (6-digit code). Then continue with **POST**
    `/v1/oauth2/authorize/confirm` to get the authorization code, and exchange
    it at `/v1/oauth2/token`.


    ## Token Management


    - **Refresh when expired:** POST `https://api.aries.com/v1/oauth2/token`
    with `grant_type=refresh_token`, `client_id`, `client_secret`,
    `refresh_token`.

    - **Using a Bearer token directly:** If you already have an access token,
    set the header `Authorization: Bearer <access_token>` on every request. The
    SDK can accept a pre-obtained token and use it until it expires.


    ## OAuth2 Scopes


    Request only the scopes your application needs. Available scopes:


    | Scope | Description |

    |-------|-------------|

    | `user:information` | View user profile and personal details |

    | `account:information` | View account balances, positions, and transaction
    history |

    | `order:execution` | Place, modify, and cancel orders |

    | `order:information` | View order history and status |

    | `position:information` | View current positions and holdings |

    | `market:information` | Access live and historical market data |

    | `calendar:information` | Access earnings, economic, and market schedule
    data |

    | `options:information` | Access options chains and expiration data |

    | `analytics:information` | View analytics, ratings, and market insights |

    | `market:supplemental` | News, company profiles, financials, filings, ETF
    data, technical analysis |


    Specify multiple scopes as a space-separated string, e.g.
    `account:information order:execution market:information`.


    ## Security Best Practices


    - **Store credentials securely** – Use environment variables or a secrets
    manager for `client_id` and `client_secret`. Never hardcode them.

    - **Handle token expiration** – Check for 401 responses and refresh the
    token using the refresh_token, then retry the request.

    - **Use HTTPS** – All authorization and token endpoints must be called over
    HTTPS.

    - **Validate state** – When using the authorization code flow, validate the
    `state` parameter on the callback to prevent CSRF.


    ## Error Handling


    - **400 Bad Request** – Invalid or missing parameters, validation failures,
    or malformed JSON. Response bodies follow the same patterns as other errors
    (flat `error` string, optional `codes`, nested `error` object, or rarely no
    body).


    - **401 Unauthorized** – Invalid or expired access token; refresh the token
    or re-authenticate. JSON bodies are not identical on every route: you may
    see a flat `error` string (sometimes with `codes`), a nested `error` object
    (`type`, `code`, `message`), or rarely an empty body


    - **403 Forbidden** – Insufficient scope or permissions for the requested
    resource. Error JSON may be flat or nested, like 400/401.


    - **404 Not Found** – Resource does not exist or is not visible. Error JSON
    may be flat or nested.


    - **429 Too Many Requests** – Rate limit exceeded; slow down and respect
    `Retry-After` when the header is present. Error JSON may be flat or nested.


    - **500 / 5xx** – Server or upstream failure; retry with backoff. Do not
    depend on a single error JSON shape; some responses may have no body.



    ---


    Endpoints in this spec: health, OAuth2 (authorize, confirm, mfa, token),
    users, accounts, orders, market data, watchlist, chart, analytics,
    calendars, company, economy, financials, indices, options, news, and
    supplemental data.
  title: Aries API — OpenAPI Specification
  version: 1.0.0
servers:
  - description: Production server
    url: https://api.aries.com
security: []
tags:
  - description: >-
      Analytics endpoints for market data analysis including top gainers,
      losers, volume leaders, sector analysis, analyst ratings, market breadth,
      and net inflow
    name: Analytics
  - description: User management and profile endpoints
    name: Users
  - description: >-
      Order management endpoints for placing, updating, canceling, and
      previewing orders
    name: Orders
  - description: Account management endpoints for positions, orders, and balances
    name: Accounts
  - description: Calendar and mergers/acquisitions endpoints
    name: Calendar
  - description: >-
      Market data endpoints for symbol search, real-time data access, and equity
      details
    name: Market Data
  - description: >-
      Watchlist endpoints for listing, creating, updating, and deleting
      watchlists
    name: Watchlist
  - description: Chart endpoints for config, symbols, history, quotes, and server time
    name: Chart
  - description: News and news sentiment endpoints
    name: News
  - description: >-
      Indices endpoints for groups, list, search, bar, bars, chart-bars,
      realtime values
    name: Indices
  - description: Logos search and sync endpoints
    name: Logos
  - description: 'Corporate actions: spinoffs, tender offers, IPO calendar, dividends'
    name: Corporate Actions
  - description: 'Economy endpoints: inflation, inflation expectations, treasury yields'
    name: Economy
  - description: >-
      Options endpoints: expiry dates, contracts, activity, trades, quotes,
      unusual activity
    name: Options
  - description: >-
      Financials: reported, statements, revenue breakdown, short volume, ratios,
      short interest
    name: Financials
  - description: Signals and bull-bear cases
    name: Signals
  - name: Company
  - name: ETF
  - name: Filings
  - name: Market
  - name: Ownership
  - name: Stocks
  - name: Stock Estimates
  - name: Stock Alternative
    description: >-
      Transcripts, company presentation, social sentiment, investment themes,
      supply chain, and ESG data
  - name: Technical Analysis
paths:
  /v1/chart/config:
    get:
      tags:
        - Chart
      summary: Get Chart Configuration
      description: >-
        Returns the chart configuration including supported resolutions and
        charting capabilities. The response includes tick-based resolutions with
        a `T` suffix, minute-based resolutions, and daily, weekly, and monthly
        multipliers used by charting clients. It also indicates whether
        intraday, daily, weekly, and monthly data are available, plus search and
        time endpoint support.
      operationId: getChartConfig
      parameters: []
      responses:
        '200':
          content:
            application/json:
              example:
                supported_resolutions:
                  - 1T
                  - 5T
                  - 10T
                  - 25T
                  - 50T
                  - 100T
                  - 250T
                  - 500T
                  - 1000T
                  - '1'
                  - '3'
                  - '5'
                  - '15'
                  - '30'
                  - '45'
                  - '60'
                  - '120'
                  - '180'
                  - '240'
                  - 1D
                  - 1W
                  - 1M
                  - 3M
                  - 6M
                  - 12M
                has_intraday: true
                intraday_multipliers:
                  - '1'
                  - '5'
                  - '15'
                  - '30'
                  - '60'
                  - '240'
                has_daily: true
                daily_multipliers:
                  - '1'
                has_weekly_and_monthly: true
                weekly_multipliers:
                  - '1'
                monthly_multipliers:
                  - '1'
                supports_search: true
                supports_group_request: false
                supports_marks: false
                supports_timescale_marks: false
                supports_time: false
              schema:
                $ref: '#/components/schemas/ChartConfig'
          description: Chart configuration retrieved successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - OAuth2:
            - market:information
components:
  schemas:
    ChartConfig:
      description: >-
        Capabilities returned for the charting API. Use this once at startup to
        configure supported resolutions and chart UI options.
      properties:
        supported_resolutions:
          description: >-
            List of supported chart resolutions, including tick-based intervals
            with a `T` suffix, minute-based intervals, and daily, weekly, and
            monthly resolutions.
          example:
            - 1T
            - 5T
            - 10T
            - 25T
            - 50T
            - 100T
            - 250T
            - 500T
            - 1000T
            - '1'
            - '3'
            - '5'
            - '15'
            - '30'
            - '45'
            - '60'
            - '120'
            - '180'
            - '240'
            - 1D
            - 1W
            - 1M
            - 3M
            - 6M
            - 12M
          items:
            type: string
          type: array
        has_intraday:
          description: Whether intraday chart data is available
          example: true
          type: boolean
        intraday_multipliers:
          description: >-
            Supported intraday multipliers used with minute-based chart
            resolutions
          example:
            - '1'
            - '5'
            - '15'
            - '30'
            - '60'
            - '240'
          items:
            type: string
          type: array
        has_daily:
          description: Whether daily chart data is available
          example: true
          type: boolean
        daily_multipliers:
          description: Supported daily multipliers
          example:
            - '1'
          items:
            type: string
          type: array
        has_weekly_and_monthly:
          description: Whether weekly and monthly chart data is available
          example: true
          type: boolean
        weekly_multipliers:
          description: Supported weekly multipliers
          example:
            - '1'
          items:
            type: string
          type: array
        monthly_multipliers:
          description: Supported monthly multipliers
          example:
            - '1'
          items:
            type: string
          type: array
        supports_group_request:
          description: Whether the API supports group requests
          example: false
          type: boolean
        supports_marks:
          description: Whether the API supports marks on charts
          example: false
          type: boolean
        supports_search:
          description: Whether the API supports symbol search
          example: true
          type: boolean
        supports_time:
          description: Whether the API supports time endpoint
          example: false
          type: boolean
        supports_timescale_marks:
          description: Whether the API supports timescale marks
          example: false
          type: boolean
      type: object
    AuthenticationErrorEnvelope:
      type: object
      description: >-
        JSON envelope where `error` is a nested object (`type`, `code`,
        `message`, …). Many services use this shape for 400, 401, 403, 404, 429,
        and 5xx when using the shared HTTP error format.
      properties:
        error:
          $ref: '#/components/schemas/AuthenticationErrorDetail'
        meta:
          type: object
          additionalProperties: true
          description: Optional metadata
    ErrorResponse:
      properties:
        codes:
          description: Structured error codes for programmatic handling
          items:
            $ref: '#/components/schemas/ErrorCode'
          type: array
        error:
          type: string
          description: >-
            Error detail as a string. Exact message content is not fixed and
            should not be hard-coded.
          example: string
        metadata:
          additionalProperties: true
          description: Additional error context
          type: object
      type: object
    AuthenticationErrorDetail:
      type: object
      description: >-
        Structured payload for the nested `error` object. Services using the
        shared Go error writer emit uppercase `type` values aligned with error
        categories (for example `VALIDATION`, `BAD_REQUEST`, `AUTHENTICATION`,
        `AUTHORIZATION`, `NOT_FOUND`, `RATE_LIMIT`, `INTERNAL`).
      properties:
        type:
          type: string
          description: >-
            Error category emitted by the shared error writer, such as
            VALIDATION, BAD_REQUEST, AUTHENTICATION, AUTHORIZATION, NOT_FOUND,
            RATE_LIMIT, or INTERNAL.
          example: AUTHENTICATION
        code:
          type: string
          description: Machine-readable code
          example: INVALID_TOKEN
        message:
          type: string
          description: >-
            Error detail as a string. Exact message content is not fixed and
            should not be hard-coded.
          example: string
        details:
          type: object
          additionalProperties: true
          description: Optional extra context
        request_id:
          type: string
          description: Request correlation id when provided
    ErrorCode:
      properties:
        code:
          description: Machine-readable error code
          example: INVALID_PASSWORD
          type: string
        description:
          description: Human-readable description of the error
          example: Password must be between 8 and 64 characters
          type: string
        field:
          description: Field name that caused the error
          example: password
          type: string
      type: object
  responses:
    BadRequest:
      description: >-
        Invalid query/path/body, malformed JSON, or failed validation.


        **Backend (shared HTTP errors):** Routes that use the shared error
        writer typically return a **nested** JSON object: `error.type` is an
        uppercase category such as `VALIDATION` or `BAD_REQUEST` (see the API
        implementation). Other routes may return the **flat** `ErrorResponse`
        shape (`error` as a string, optional `codes`). The body may rarely be
        empty.


        **OpenAPI:** Every operation’s **400** response references this
        component so the documented schema and examples stay aligned.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/AuthenticationErrorEnvelope'
              - $ref: '#/components/schemas/ErrorResponse'
            description: >-
              400 responses commonly use a nested `error` object (`type`,
              `code`, `message`, optional `details`). Some services still return
              flat `ErrorResponse` (`error` string, optional `codes`).
          examples:
            nested_shared_http_error:
              summary: Nested error (typical for shared WriteHTTPError-style responses)
              value:
                error:
                  type: VALIDATION
                  code: VALIDATION_ERROR
                  message: Query parameter validation failed
                  details:
                    fieldName: field is required
            nested_bad_request:
              summary: Nested error (BAD_REQUEST / invalid JSON)
              value:
                error:
                  type: BAD_REQUEST
                  code: INVALID_JSON
                  message: string
            flat_string:
              summary: Flat error string
              value:
                error: string
            flat_with_codes:
              summary: Flat error with field codes (some services)
              value:
                error: string
                codes:
                  - field: string
                    code: string
                    description: string
    Unauthorized:
      description: >-
        Authentication failed: missing credentials, invalid JWT, or expired
        access token.


        **Response body variants:** Some routes return JSON with a string
        `error` field (and optionally `codes` / `metadata`). Others return JSON
        where `error` is a structured object (`type`, `code`, `message`, and
        optionally `details`, `request_id`). In edge cases (for example certain
        gateway or middleware paths) the response may have **no body** even
        though the status is 401—clients should treat 401 as unauthenticated and
        refresh or re-authenticate regardless of body shape.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/ErrorResponse'
              - $ref: '#/components/schemas/AuthenticationErrorEnvelope'
            description: >-
              401 responses may use a flat `ErrorResponse` shape or a nested
              `error` object. Inspect `error`: if it is a string, use the flat
              shape; if it is an object, use the structured shape.
          examples:
            flat_message:
              summary: Flat error string (typical)
              value:
                error: string
            flat_with_codes:
              summary: Flat error with structured codes
              value:
                error: string
                codes:
                  - code: string
                    description: string
            nested_error_object:
              summary: Nested error (shared HTTP error format)
              value:
                error:
                  type: AUTHENTICATION
                  code: INVALID_TOKEN
                  message: string
    Forbidden:
      description: >-
        Authenticated but not allowed to perform this action or access this
        resource (insufficient scope or role).


        **Response body variants:** Flat `ErrorResponse` or nested `error`
        object, same pattern as 400/401.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/ErrorResponse'
              - $ref: '#/components/schemas/AuthenticationErrorEnvelope'
            description: 403 responses may use a flat or nested error shape.
          examples:
            flat:
              summary: Flat message
              value:
                error: string
            nested:
              summary: Nested error (shared HTTP error format)
              value:
                error:
                  type: AUTHORIZATION
                  code: INSUFFICIENT_SCOPE
                  message: string
    NotFound:
      description: >-
        The requested resource does not exist or is not visible to this caller.


        **Response body variants:** Flat `ErrorResponse` or nested `error`
        object.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/ErrorResponse'
              - $ref: '#/components/schemas/AuthenticationErrorEnvelope'
            description: 404 responses may use a flat or nested error shape.
          examples:
            flat:
              summary: Flat message
              value:
                error: string
            nested:
              summary: Nested error (shared HTTP error format)
              value:
                error:
                  type: NOT_FOUND
                  code: RESOURCE_NOT_FOUND
                  message: string
    InternalServerError:
      description: >-
        Unexpected server error or upstream failure. **Retry with exponential
        backoff**; do not assume a specific JSON body shape.


        **Response body variants:** Flat `ErrorResponse`, nested `error` object,
        or occasionally a minimal message. Some paths may return **no body**.
      content:
        application/json:
          examples:
            flat_string:
              summary: Flat error string
              value:
                error: string
            nested_error_object:
              summary: Nested error (shared HTTP error format)
              value:
                error:
                  type: INTERNAL
                  code: INTERNAL_ERROR
                  message: string
          schema:
            oneOf:
              - $ref: '#/components/schemas/ErrorResponse'
              - $ref: '#/components/schemas/AuthenticationErrorEnvelope'
            description: 5xx responses may use a flat or nested error shape.
  securitySchemes:
    OAuth2:
      type: oauth2
      description: >-
        OAuth2 Bearer token: obtain an access token from the token endpoint and
        send it in the Authorization header.
      flows:
        clientCredentials:
          tokenUrl: https://api.aries.com/v1/oauth2/token
          refreshUrl: https://api.aries.com/v1/oauth2/token
          scopes:
            user:information: View user profile and personal details
            account:information: View account balances, positions, and transaction history
            order:execution: Place, modify, and cancel orders
            order:information: View order history and status
            position:information: View current positions and holdings
            market:information: Access live and historical market data
            calendar:information: Access earnings, economic, and market schedule data
            options:information: Access options chains and expiration data
            analytics:information: View analytics, ratings, and market insights
            market:supplemental: >-
              News, company profiles, financials, filings, ETF data, technical
              analysis
            user:management: >-
              Manage user-scoped resources such as watchlists and other saved
              configuration.
        authorizationCode:
          authorizationUrl: https://app.aries.com/oauth2/authorize
          tokenUrl: https://api.aries.com/v1/oauth2/token
          refreshUrl: https://api.aries.com/v1/oauth2/token
          scopes:
            user:information: View user profile and personal details
            account:information: View account balances, positions, and transaction history
            order:execution: Place, modify, and cancel orders
            order:information: View order history and status
            position:information: View current positions and holdings
            market:information: Access live and historical market data
            calendar:information: Access earnings, economic, and market schedule data
            options:information: Access options chains and expiration data
            analytics:information: View analytics, ratings, and market insights
            market:supplemental: >-
              News, company profiles, financials, filings, ETF data, technical
              analysis
            user:management: >-
              Manage user-scoped resources such as watchlists and other saved
              configuration.

````