🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

eToro Apps

by @marian2js

Enables agents to interact with the eToro API to access market data, portfolio and social features, and execute trades programmatically. Supports both OAuth...

Versionv1.0.0
Downloads867
Stars⭐ 1
TERMINAL
clawhub install etoro-apps

πŸ“– About This Skill


name: etoro-apps version: 1.0.0 description: Enables agents to interact with the eToro API to access market data, portfolio and social features, and execute trades programmatically. Supports both OAuth SSO and manual API key authentication. homepage: https://api-portal.etoro.com/ metadata: { "openclaw": { "emoji": "πŸ“ˆ", "category": "finance", "api_base": "https://public-api.etoro.com/api/v1", }, }

eToro Public API

Base URL: https://public-api.etoro.com/api/v1

About

This skill allows to interact with the user's eToro account programatically, including executing trades.

Authentication & Required Headers

The eToro API supports two authentication methods. Both use the same base URL and endpoints β€” only the auth headers differ.

Method 1 β€” OAuth SSO (Bearer Token)

If the user authenticated via "Login with eToro" (SSO/OAuth), an access_token is available from the token exchange.

Headers (every request):

  • x-request-id: unique UUID per request
  • Authorization: Bearer
  • Where access_token comes from:

    1. User clicks "Login with eToro" β†’ redirects to https://www.etoro.com/sso/ with PKCE challenge. 2. User authenticates on eToro's side. 3. eToro redirects back with an authorization code. 4. The code is exchanged for tokens via POST https://www.etoro.com/sso/oidc/token: - grant_type=authorization_code - code= - redirect_uri= - code_verifier= - Plus Authorization: Basic header 5. Response contains: - access_token β€” this is the Bearer token for API calls (~2130 chars, JWT) - id_token β€” JWT with user identity (sub claim = 128-char encoded user ID) - token_type: "Bearer" - expires_in: (varies)

    Example:

    curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \
      -H "x-request-id: " \
      -H "Authorization: Bearer "
    

    Method 2 β€” Manual API Keys

    If the user provides API keys manually (no OAuth), use key-based auth.

    Keys (request from the user on install)

  • Public API Key: application
  • User Key: user account
  • Environment: Real Portfolio or Virtual Portfolio (real/demo)
  • Key generation (user-facing):

    1. Log in to eToro. 2. Settings > Trading. 3. Create New Key. 4. Choose Environment (Real or Virtual/Demo) and Permissions (Read or Write). 5. Verify identity and copy the generated User Key.

    Headers (every request):

  • x-request-id: unique UUID per request
  • x-api-key: Public API Key ()
  • x-user-key: User Key ()
  • Example:

    curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \
      -H "x-request-id: " \
      -H "x-api-key: " \
      -H "x-user-key: "
    

    Choosing the Auth Method in Code

    When making requests, check which credentials are available:

    if (ctx.accessToken) {
      // SSO auth β€” Bearer token from OAuth token exchange
      headers["Authorization"] = Bearer ${ctx.accessToken};
    } else {
      // Manual API key auth
      headers["x-api-key"] = ctx.apiKey;
      headers["x-user-key"] = ctx.userKey;
    }
    

    Request Conventions

  • All paths below are relative to the Base URL (which already includes /api/v1).
  • Example: GET /watchlists means GET https://public-api.etoro.com/api/v1/watchlists.
  • Query params go in the URL, path params go in the URL path.
  • For query params that are documented as array, send them as comma-separated values (e.g., instrumentIds=1001,1002).
  • Pagination patterns vary by endpoint:
  • - Search: pageNumber, pageSize - People search & trade history: page, pageSize - Feeds: take, offset - Watchlist items listing: pageNumber, itemsPerPage
  • Casing matters for request bodies:
  • - Trading execution uses PascalCase fields (e.g., InstrumentID, IsBuy, Leverage). - Market close body uses InstrumentId (capital I, lowercase d). - Watchlist items use ItemId, ItemType, ItemRank. - Feeds post body uses lower camel (owner, message, tags, mentions, attachments).
  • Some responses may use different casing for similar concepts (e.g., instrumentId vs InstrumentID). When extracting IDs, handle both if present.
  • Demo vs Real Trading

  • Use demo execution endpoints (contain /demo/) for testing and paper trading.
  • Use non-demo execution endpoints for real trading.
  • For portfolio/PnL:
  • - Demo: /trading/info/demo/* - Real: /trading/info/portfolio and /trading/info/real/pnl
  • Ensure your key environment matches the endpoint (Virtual vs Real). Each User Key is associated with a specific environment.
  • Use Defaults

  • Important: You don't need to specify all parameters. If the user doesn't specify leverage for example, don't send it on the API request.
  • Quick Start (Demo Trade)

    1. Resolve instrumentId using search. fields is required on search requests.

    curl -X GET "https://public-api.etoro.com/api/v1/market-data/search?internalSymbolFull=BTC&fields=instrumentId,internalSymbolFull,displayname" \
      -H "Authorization: Bearer " \
      -H "x-request-id: "
    

    2. Place a demo market order by amount (PascalCase body):

    curl -X POST "https://public-api.etoro.com/api/v1/trading/execution/demo/market-open-orders/by-amount" \
      -H "Authorization: Bearer " \
      -H "x-request-id: " \
      -H "Content-Type: application/json" \
      -d '{
        "InstrumentID": 100000,
        "IsBuy": true,
        "Leverage": 1,
        "Amount": 100
      }'
    

    > Note: The examples above use OAuth (Bearer token). For API key auth, replace the Authorization header with x-api-key and x-user-key headers instead.

    Common IDs

  • instrumentId: from Search or Instruments metadata
  • positionId: from Portfolio endpoints
  • orderId: from execution responses or Portfolio endpoints
  • marketId: used by instrument feed endpoints (typically available in instrument metadata/search fields)
  • userId: numeric eToro user ID (often referred to as CID in responses; discover via People endpoints/search)
  • watchlistId: from watchlists list/create endpoints
  • Market Data (Requests)

    Search instruments

  • GET /market-data/search
  • Required query: fields (comma-separated list of instrument fields to return)
  • Optional: searchText, pageSize, pageNumber, sort
  • The Search endpoint supports filtering by fields returned in results; for exact symbol lookup, use internalSymbolFull as a query param and verify the exact match.
  • Recommended minimal fields when you need IDs: include the instrument identifier (may appear as instrumentId or InstrumentID), plus internalSymbolFull and displayname (and marketId if you plan to use Feeds).
  • Metadata

  • GET /market-data/instruments
  • Filters: instrumentIds, exchangeIds, stocksIndustryIds, instrumentTypeIds.

    Prices & history

  • GET /market-data/instruments/rates
  • Required: instrumentIds (comma-separated).
  • GET /market-data/instruments/history/closing-price
  • Returns historical closing prices for all instruments (bulk).
  • GET /market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}
  • direction: asc or desc. candlesCount max 1000. Use only supported interval values (confirm via docs if unsure).

    Reference data

  • GET /market-data/exchanges (optional exchangeIds)
  • GET /market-data/instrument-types
  • GET /market-data/stocks-industries (optional stocksIndustryIds)
  • Trading Execution (Requests)

    > Requires appropriate permissions (typically Write) and the correct environment (Demo vs Real).

    Market Open Orders (by amount)

    Endpoints:

  • POST /trading/execution/demo/market-open-orders/by-amount
  • POST /trading/execution/market-open-orders/by-amount
  • Body (PascalCase, JSON):

  • Required: InstrumentID, IsBuy, Leverage, Amount
  • Optional: StopLossRate, TakeProfitRate, IsTslEnabled, IsNoStopLoss, IsNoTakeProfit
  • Market Open Orders (by units)

    Endpoints:

  • POST /trading/execution/demo/market-open-orders/by-units
  • POST /trading/execution/market-open-orders/by-units
  • Body (PascalCase, JSON):

  • Required: InstrumentID, IsBuy, Leverage, AmountInUnits
  • Optional: StopLossRate, TakeProfitRate, IsTslEnabled, IsNoStopLoss, IsNoTakeProfit
  • Cancel Market Open Orders

    Endpoints:

  • DELETE /trading/execution/demo/market-open-orders/{orderId}
  • DELETE /trading/execution/market-open-orders/{orderId}
  • Market Close Orders

    Endpoints:

  • POST /trading/execution/demo/market-close-orders/positions/{positionId}
  • POST /trading/execution/market-close-orders/positions/{positionId}
  • DELETE /trading/execution/demo/market-close-orders/{orderId}
  • DELETE /trading/execution/market-close-orders/{orderId}
  • Body (JSON):

  • Required: InstrumentId
  • Optional: UnitsToDeduct (number or null)
  • Partial close: set UnitsToDeduct. Full close: set UnitsToDeduct to null. You must close by positionId, not by symbol.

    Market-if-touched (Limit) Orders

    Endpoints:

  • POST /trading/execution/demo/limit-orders
  • DELETE /trading/execution/demo/limit-orders/{orderId}
  • POST /trading/execution/limit-orders
  • DELETE /trading/execution/limit-orders/{orderId}
  • Body (PascalCase, JSON):

  • Required: InstrumentID, IsBuy, Leverage, Rate, and one of Amount or AmountInUnits
  • Optional: StopLossRate, TakeProfitRate, IsTslEnabled, IsNoStopLoss, IsNoTakeProfit
  • Do not send: IsDiscounted, CID
  • Trading Info & Portfolio (Requests)

  • GET /trading/info/demo/pnl
  • GET /trading/info/real/pnl
  • GET /trading/info/demo/portfolio
  • GET /trading/info/portfolio
  • Use these to discover positionId and orderId for close/cancel flows.
  • GET /trading/info/trade/history
  • Required: minDate (YYYY-MM-DD). Optional: page, pageSize.

    Watchlists (Requests)

    User watchlists

  • GET /watchlists
  • Optional: itemsPerPageForSingle, ensureBuiltinWatchlists, addRelatedAssets.
  • GET /watchlists/{watchlistId}
  • Optional: pageNumber, itemsPerPage.
  • POST /watchlists
  • Query: name (required), type, dynamicQuery (optional). (Uses query params, not a JSON body.)
  • PUT /watchlists/{watchlistId}
  • Query: newName (required). (Uses query params, not a JSON body.)
  • DELETE /watchlists/{watchlistId}
  • Watchlist items (body schema)

    WatchlistItemDto fields:

  • ItemId (required, int)
  • ItemType (required, string: Instrument or Person)
  • ItemRank (optional, int)
  • Endpoints:

  • POST /watchlists/{watchlistId}/items
  • PUT /watchlists/{watchlistId}/items
  • DELETE /watchlists/{watchlistId}/items
  • Example body:

    [
      { "ItemId": 12345, "ItemType": "Instrument", "ItemRank": 1 },
      { "ItemId": 67890, "ItemType": "Instrument", "ItemRank": 2 }
    ]
    

    Default watchlists

  • POST /watchlists/default-watchlist/selected-items
  • GET /watchlists/default-watchlists/items
  • Optional: itemsLimit, itemsPerPage.
  • POST /watchlists/newasdefault-watchlist
  • Query: name (required), type, dynamicQuery (optional).
  • PUT /watchlists/setUserSelectedUserDefault/{watchlistId}
  • PUT /watchlists/rank/{watchlistId}
  • Query: newRank (required).

    Public watchlists

  • GET /watchlists/public/{userId}
  • GET /watchlists/public/{userId}/{watchlistId}
  • Feeds (Requests)

    Read feeds

  • GET /feeds/instrument/{marketId}
  • Optional: requesterUserId, take, offset, badgesExperimentIsEnabled, reactionsPageSize.
  • GET /feeds/user/{userId}
  • Optional: requesterUserId, take, offset, badgesExperimentIsEnabled, reactionsPageSize.

    Notes:

  • marketId is associated with an instrument (typically available via instrument metadata/search if you include it in fields).
  • userId is a numeric user identifier (CID). If you only have a username, discover the numeric ID via People endpoints (see User Info & Analytics).
  • Create post

  • POST /feeds/post
  • Body fields (lower camel, JSON):
  • - owner (int) - message (string) - tags: { "tags": [{ "name": "...", "id": "..." }] } - mentions: { "mentions": [{ "userName": "...", "id": "...", "isD irect": true }] } - attachments: array of objects with url, title, host, description, mediaType, and optional media.

    Minimal example:

    { "message": "Hello eToro feed!" }
    

    Curated Lists & Recommendations (Requests)

  • GET /curated-lists
  • GET /market-recommendations/{itemsCount}
  • Popular Investors (Copiers)

  • GET /pi-data/copiers
  • User Info & Analytics (Requests)

  • GET /user-info/people
  • Optional: usernames, cidList. Use this to map username ↔ CID (userId) when you need numeric userId for feeds/public watchlists.
  • GET /user-info/people/search
  • Required: period. Optional: page, pageSize, sort, popularInvestor, gainMax, maxDailyRiskScoreMin, maxDailyRiskScoreMax, maxMonthlyRiskScoreMin, maxMonthlyRiskScoreMax, weeksSinceRegistrationMin, countryId, instrumentId, instrumentPctMin, instrumentPctMax, isTestAccount, and other filters.
  • GET /user-info/people/{username}/gain
  • GET /user-info/people/{username}/daily-gain
  • Required: minDate, maxDate, type (Daily or Period).
  • GET /user-info/people/{username}/portfolio/live
  • GET /user-info/people/{username}/tradeinfo
  • Required: period (e.g., LastTwoYears).

    Responses & Schemas

    For response schemas and full examples, refer to:

  • https://api-portal.etoro.com/
  • MCP server: https://api-portal.etoro.com/mcp