SnapTrade Authentication API

Register and authenticate users with SnapTrade.

Operations 5

GET /snapTrade/listUsers List all users #
POST /snapTrade/registerUser Register user #
DELETE /snapTrade/deleteUser Delete user #
POST /snapTrade/login Generate Connection Portal URL #
POST /snapTrade/resetUserSecret Rotate user secret #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/snaptrade:snaptrade-authentication-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

snaptrade-authentication-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  description: 'Connect brokerage accounts to your app for live positions and trading.


    ## Rate limiting


    Two limits apply to requests signed with your `clientId`. The stricter one

    wins, and exceeding either returns `429 Too Many Requests`.


    - **Customer-level** — 250 requests/minute by default, scoped to your

    `clientId` and applied across all endpoints. Reported in

    `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`.

    - **Account-level** — 10 requests/minute per account, scoped to

    (`clientId`, `accountId`). All covered operations for one account draw on

    the same bucket — reading balances and reading positions share it — and

    enforcement does not depend on the HTTP method, so updating an account

    consumes the same bucket as reading it. Only enforced for Personal users,

    and only for integrations it has been rolled out to — it is not yet in

    force for every Personal integration. It also does not apply on every

    operation that documents a 429 below. Where it applies it is reported in

    `X-RateLimit-Account-Limit`, `X-RateLimit-Account-Remaining` and

    `X-RateLimit-Account-Reset`. Do not read the absence of those headers as

    proof the limit is off — some configurations omit the rate limit headers

    while still enforcing the limit, so header absence tells you nothing

    about your allowance.


    On a 429, `X-RateLimit-Remaining: 0` means you hit the customer-level limit

    and `X-RateLimit-Account-Remaining: 0` means the account-level one. Wait for

    the corresponding `*-Reset` value (seconds) before retrying, or fall back to

    exponential backoff with jitter.


    Not every 429 is explained by those headers. A separate

    per-authenticated-user limit, reported in no `X-RateLimit-*` header, covers

    OAuth-authenticated requests and signed requests in configurations where the

    customer-level limit is not in effect — on the operations that use the

    default throttles. A few operations override those and are governed by the

    customer-level limit alone. The two do not stack: a signed request

    governed by the customer-level limit above is not additionally subject to the

    per-user one. If a 429 arrives with no header at zero — or with no

    `X-RateLimit-*` headers at all — honour `Retry-After` and back off. Treat the

    remaining counts as a hint, not a guarantee that the next request will

    succeed.


    Because the customer-level limit applies everywhere, any signed request can

    return 429.


    **OAuth-authenticated requests are an exception.** They are not subject to

    the customer-level limit and do not receive `X-RateLimit-Limit`,

    `X-RateLimit-Remaining` or `X-RateLimit-Reset` — do not wait on those headers

    or design around a customer-level allowance on this path. The account-level

    limit still applies to them on the account-data endpoints above, reported in

    the `X-RateLimit-Account-*` headers. On operations using the default

    throttles the per-user limit above applies to them as well, so an OAuth

    request can be rejected while the account headers still show capacity; on

    the few operations that override those throttles, OAuth callers have no

    per-user ceiling at all. Drive retries from `Retry-After` and exponential

    backoff with jitter rather than from the headers.


    See https://docs.snaptrade.com/docs/ratelimiting.'
  version: 1.0.0
  title: SnapTrade Authentication API
  termsOfService: N/A
  contact:
    email: api@snaptrade.com
  x-konfig-ignore:
    potential-incorrect-type: true
  x-readme:
    explorer-enabled: false
servers:
- description: SnapTrade Production API
  url: https://api.snaptrade.com
security:
- PartnerSignature: []
  PartnerClientId: []
  PartnerTimestamp: []
tags:
- name: Authentication
  description: Register and authenticate users with SnapTrade.
paths:
  /snapTrade/listUsers:
    get:
      tags:
      - Authentication
      summary: List all users
      operationId: Authentication_listSnapTradeUsers
      description: Returns a list of all registered user IDs. Please note that the response is not currently paginated.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserList'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/400FailedRequestResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/404FailedRequestResponse'
        '500':
          description: Unexpected Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/500UnexpectedExceptionResponse'
  /snapTrade/registerUser:
    post:
      tags:
      - Authentication
      summary: Register user
      description: 'Registers a new SnapTrade user under your Client ID. A user secret will be automatically generated for you and must be properly stored in your system.

        Most SnapTrade operations require a user ID and user secret to be passed in as parameters.'
      operationId: Authentication_registerSnapTradeUser
      requestBody:
        $ref: '#/components/requestBodies/RegisterUserRequestBody'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserIDandSecret'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/400FailedRequestResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/404FailedRequestResponse'
        '500':
          description: Unexpected Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/500UnexpectedExceptionResponse'
  /snapTrade/deleteUser:
    delete:
      tags:
      - Authentication
      summary: Delete user
      operationId: Authentication_deleteSnapTradeUser
      description: Deletes a registered user and all associated data. This action is irreversible. This API is asynchronous and will return a 200 status code if the request is accepted. The user and all associated data will be queued for deletion. Once deleted, a `USER_DELETED` webhook will be sent.
      parameters:
      - in: query
        required: true
        name: userId
        schema:
          $ref: '#/components/schemas/UserID'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteUserResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/400FailedRequestResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/403FailedRequestResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/404FailedRequestResponse'
        '500':
          description: Unexpected Error
  /snapTrade/login:
    post:
      tags:
      - Authentication
      summary: Generate Connection Portal URL
      operationId: Authentication_loginSnapTradeUser
      description: 'Authenticates a SnapTrade user and returns the Connection Portal URL used for connecting brokerage accounts. Please check this guide for how to integrate the Connection Portal into your app.


        Please note that the returned URL expires in 5 minutes.'
      parameters:
      - in: query
        required: true
        name: userId
        schema:
          $ref: '#/components/schemas/UserID'
      - in: query
        required: true
        name: userSecret
        schema:
          $ref: '#/components/schemas/UserSecret'
      requestBody:
        $ref: '#/components/requestBodies/SnapTradeLoginUserRequestBody'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                oneOf:
                - $ref: '#/components/schemas/LoginRedirectURI'
                - $ref: '#/components/schemas/encryptedResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/400FailedRequestResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/403FailedRequestResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/404FailedRequestResponse'
        '500':
          description: Unexpected Error
  /snapTrade/resetUserSecret:
    post:
      tags:
      - Authentication
      summary: Rotate user secret
      description: Rotates the secret for a SnapTrade user. You might use this if `userSecret` is compromised. Please note that if you call this endpoint and fail to save the new secret, you'll no longer be able to access any data for this user, and your only option will be to delete and recreate the user, then ask them to reconnect.
      operationId: Authentication_resetSnapTradeUserSecret
      requestBody:
        $ref: '#/components/requestBodies/ResetUserSecretRequestBody'
      responses:
        '200':
          description: New user secret is generated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserIDandSecret'
        '400':
          description: Bad Request. Could be caused by various reasons. Error message is provided in response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/400FailedRequestResponse'
        '401':
          description: Failed authentication. Wrong clientId, userId or userSecret provided
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/401FailedRequestResponse'
        '403':
          description: Forbidden. The user's secret is managed by a first-party app and cannot be reset here
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/403FailedRequestResponse'
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/500UnexpectedExceptionResponse'
components:
  requestBodies:
    RegisterUserRequestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SnapTradeRegisterUserRequestBody'
    SnapTradeLoginUserRequestBody:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SnapTradeLoginUserRequestBody'
    ResetUserSecretRequestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/UserIDandSecret'
  schemas:
    UserList:
      description: List of registered SnapTrade user IDs
      type: array
      items:
        $ref: '#/components/schemas/UserID'
      example:
      - user1
      - user2
      - user3
    404FailedRequestResponse:
      description: Example for failed request response
      type: object
      properties:
        default_detail:
          example: The requested resource does not exist.
        default_code:
          example: 1011
    LoginRedirectURI:
      description: Redirect uri upon successful login
      type: object
      properties:
        redirectURI:
          description: Connection Portal link to redirect user to connect a brokerage account.
          type: string
          example: https://app.snaptrade.com/snapTrade/redeemToken?token=npVKchZrL0MYIHTusGfADT74r4xXpHkmbxbQDmt0RINLXbQ5cWsvGkPSgMQRxz8/cnxjzL9T2NWLuHuDyidHiCNeXXTb/tVhzC2olSyfxWW6DRrkUppArGCdmkIHyBMzog6C55P8yoqzcGer5Hml0Q%3D%3D&clientId=WEALTHLY&broker=ROBINHOOD&connectionPortalVersion=v4&sessionId=cf371bb4-a475-4f17-ab94-d0fee699960d
        sessionId:
          description: ID to identify the connection portal session.
          type: string
          example: cf371bb4-a475-4f17-ab94-d0fee699960d
    SnapTradeLoginUserRequestBody:
      description: Data to login a user via SnapTrade Partner
      type: object
      properties:
        broker:
          description: Slug of the brokerage to connect the user to. See [the integrations page](https://support.snaptrade.com/brokerages) for a list of supported brokerages and their slugs.
          type: string
          example: ALPACA
        immediateRedirect:
          description: When set to `true`, user will be redirected back to the partner's site instead of the connection portal. This parameter is ignored if the connection portal is loaded inside an iframe. See the [guide on ways to integrate the connection portal](/docs/implement-connection-portal) for more information.
          type: boolean
          example: true
        customRedirect:
          description: URL to redirect the user to after the user connects their brokerage account. This parameter is ignored if the connection portal is loaded inside an iframe. See the [guide on ways to integrate the connection portal](/docs/implement-connection-portal) for more information.
          type: string
          example: https://snaptrade.com
        reconnect:
          description: The UUID of the brokerage connection to be reconnected. This parameter should be left empty unless you are reconnecting a disabled connection. See the [guide on fixing broken connections](/docs/fix-broken-connections) for more information.
          type: string
          example: 8b5f262d-4bb9-365d-888a-202bd3b15fa1
        connectionType:
          description: 'Determines connection permissions (default: read) - `read`: Data access only. - `trade`: Data and trading access. - `trade-if-available`: Attempts to establish a trading connection if the brokerage supports it, otherwise falls back to read-only access automatically.

            '
          type: string
          enum:
          - read
          - trade
          - trade-if-available
          default: read
        showCloseButton:
          description: Controls whether the close (X) button is displayed in the connection portal. When false, you control closing behavior from your app. Defaults to true.
          type: boolean
          example: true
        darkMode:
          description: Enable dark mode for the connection portal. Defaults to false.
          type: boolean
          example: true
        locale:
          description: 'Language the connection portal renders in. `en` and `pt-BR` are the languages we ship; any other language is rejected with a 400. Matching is case- and separator-insensitive, so `pt-br`, `pt-BR` and `pt_BR` are equivalent, and a regional tag resolves to the language when we ship it, so `en-US` renders `en`. Deliberately not an enum: those equivalent spellings are all accepted by the API, and an enum would have generated SDKs reject them before the request is sent. Screens without translated copy fall back to English individually. Defaults to `en`.

            '
          type: string
          example: pt-BR
          default: en
        connectionPortalVersion:
          description: Sets the connection portal version to render. Currently only `v4` is supported and is the default. All other versions are deprecated and will automatically be set to v4.
          type: string
          example: v4
          enum:
          - v4
          - v3
          - v2
          default: v4
    DeleteUserResponse:
      type: object
      properties:
        status:
          description: This is always `deleted` when a user is queued for deletion.
          type: string
          example: deleted
        detail:
          description: Human friendly message about the deletion status.
          type: string
          example: User queued for deletion; please wait for webhook for confirmation.
        userId:
          $ref: '#/components/schemas/UserID'
    400FailedRequestResponse:
      description: Example for failed request response
      type: object
      properties:
        default_detail:
          example: Unable to verify data sent
        default_code:
          example: 1076
    UserIDandSecret:
      type: object
      properties:
        userId:
          $ref: '#/components/schemas/UserID'
        userSecret:
          $ref: '#/components/schemas/UserSecret'
    encryptedResponse:
      description: "This response consists of 2 different components that must be decrypted to obtain the decrypted message\n\n* Decrypting the encryptedSharedKey\n\n  The encrypted shared key is a shared key that was randomly generated by SnapTrade and encrypted using the users SSH public key provided when registering the user\n  It is needed to decrypt the message in step 2.\n\n  To decrypt the shared key, the user should have access to their SSH private key stored locally in their device\n\n  An example Python code on how to decrypt the shared key is shown below\n\n  ```\n  def decrypt_rsa_message(self, encrypted_message):\n      from Crypto.Cipher import PKCS1_OAEP\n      from Crypto.PublicKey import RSA\n      from base64 import b64decode\n\n      f = open('private.pem', 'r')\n      private_key = RSA.import_key(f.read())\n      cipher = PKCS1_OAEP.new(private_key)\n\n      return cipher.decrypt(b64decode(encrypted_message.encode())).decode()\n  ```\n\n* Decrypting the encryptedMessageData\n\n   The data meant to be returned by an endpoint can be obtained by decrypting the encrypted message\n\n   An encrypted message is a message that is encrypted using AES - MODE OCB with the shared key obtained in step one\n\n  An example code to decrypt the encrypted message is shown below\n\n  ```\n  def decrypt_aes_message(self, shared_key, encrypted_message):\n      from Crypto.Cipher import AES\n      from base64 import b64decode\n\n      encrypted_msg = b64decode(encrypted_message[\"encryptedMessage\"].encode())\n      tag = b64decode(encrypted_message[\"tag\"].encode())\n      nonce = b64decode(encrypted_message[\"nonce\"].encode())\n      cipher = AES.new(shared_key.encode(), AES.MODE_OCB, nonce=nonce)\n\n      return cipher.decrypt_and_verify(encrypted_msg, tag).decode()\n  ```\n"
      type: object
      additionalProperties: false
      properties:
        encryptedSharedKey:
          type: string
          example: 5UEaY9QGzcNTr8y2jGDUI79jY1OdfK9x
        encryptedMessageData:
          type: object
          properties:
            encryptedMessage:
              type: string
              example: 9Xy05vqZOfp0OpW5fLAaDw==
            tag:
              type: string
              example: mWZPkpQh5ktbcz6N7cTRmQ==
            nonce:
              type: string
              example: None
    UserSecret:
      description: SnapTrade User Secret. This is a randomly generated string and should be stored securely. If compromised, please rotate it via the [rotate user secret endpoint](/reference/Authentication/Authentication_resetSnapTradeUserSecret).
      type: string
      example: adf2aa34-8219-40f7-a6b3-60156985cc61
    SnapTradeRegisterUserRequestBody:
      description: Data required to register a user via SnapTrade Partner
      type: object
      required:
      - userId
      properties:
        userId:
          $ref: '#/components/schemas/UserID'
    403FailedRequestResponse:
      description: Example for failed request response
      type: object
      properties:
        default_detail:
          example: User does not have permission to access this resource
        default_code:
          example: 1066
    401FailedRequestResponse:
      description: Example for failed request response
      type: object
      properties:
        default_detail:
          example: Unable to verify signature sent
        default_code:
          example: 1076
    500UnexpectedExceptionResponse:
      description: Example for a response that failed for unexpected reasons
      type: object
      properties:
        detail:
          example: Encountered an unexpected exception.
        status_code:
          example: 500
        code:
          example: 1000
    UserID:
      description: SnapTrade User ID. This is chosen by the API partner and can be any string that is a) unique to the user, and b) immutable for the user. It is recommended to NOT use email addresses for this property because they are usually not immutable.
      type: string
      example: snaptrade-user-123
  securitySchemes:
    PartnerSignature:
      type: apiKey
      in: header
      name: Signature
    PartnerClientId:
      type: apiKey
      in: query
      name: clientId
    PartnerTimestamp:
      type: apiKey
      in: query
      name: timestamp