we-promise/sure · error · Provider::Trading212::ApiError

Trading 212 API error (status #{response.code})

Error message

Trading 212 API error (status #{response.code})

What it means

Provider::Trading212 raises ApiError for any HTTP status not otherwise mapped in handle_response - i.e. everything except 200/201 (success), 401/403 (AuthenticationError) and 429 (RateLimitError). The error carries status_code and response_body accessors so callers can branch on the exact status.

Source

Thrown at app/models/provider/trading212.rb:139

    def extract_cursor(next_page_path)
      uri = URI.parse("https://placeholder#{next_page_path}")
      params = URI.decode_www_form(uri.query.to_s).to_h
      params["cursor"]
    rescue URI::InvalidURIError
      nil
    end

    def handle_response(response)
      case response.code
      when 200, 201
        response.parsed_response
      when 401, 403
        raise AuthenticationError, "Trading 212 authentication failed (#{response.code}). Check your API key."
      when 429
        raise RateLimitError, "Trading 212 rate limit exceeded. Please wait before retrying."
      else
        raise ApiError.new(
          "Trading 212 API error (status #{response.code})",
          status_code: response.code,
          response_body: response.body
        )
      end
    end

    def with_retries(label, max_retries: 3)
      attempt = 0
      begin
        attempt += 1
        yield
      rescue *RETRYABLE_ERRORS => e
        raise if attempt >= max_retries
        delay = [ 2**attempt, 30 ].min
        DebugLogEntry.capture(
          category: "sync",
          level: "warn",

View on GitHub (pinned to e69894adb9)

Solutions

  1. Inspect e.status_code and e.response_body first - the fix depends entirely on the status
  2. If 404: verify the endpoint path and that environment ("live" vs "demo") matches where the key was created
  3. If 5xx: retry later with backoff; Trading212 equities API has frequent transient failures
  4. If 400/422: log response_body for the exact validation message Trading212 returns and fix the request params
  5. Confirm the account has 'API access' enabled in Trading212 settings for the endpoints being called

Example fix

# before
summary = client.fetch_account_summary

# after
begin
  summary = client.fetch_account_summary
rescue Provider::Trading212::ApiError => e
  Rails.logger.warn("T212 #{e.status_code}: #{e.response_body}")
  raise if e.status_code.to_i / 100 == 4 # client/config problem - do not retry
  sleep(30) && retry if (retries += 1) < 3 # 5xx - transient
  raise
end
Defensive patterns

Strategy: try-catch

Validate before calling

# Confirm environment matches the key before first call
expected = item.environment == "demo" ? "demo.trading212.com" : "live.trading212.com"
raise ArgumentError, "environment/base_uri mismatch" unless base_uri.include?(expected)

Type guard

def t212_api_error?(err)
  err.is_a?(Provider::Trading212::ApiError)
end

def retryable?(err)
  err.status_code.to_i / 100 == 5
end

Try / catch

retries = 0
begin
  client.fetch_positions
rescue Provider::Trading212::ApiError => e
  retry if (e.status_code.to_i / 100) == 5 && (retries += 1) < 3 && sleep(2**retries * 5)
  log_t212_failure(e.status_code, e.response_body)
  raise
end

Prevention

When it happens

Trigger: Calling /equity/account/summary, /equity/positions, /equity/history/* endpoints against the wrong environment (live key against demo.trading212.com returns 404/403-shaped failures that land here); Trading212 5xx outages; 404 for endpoints disabled on the account's API plan; malformed query params producing 400/422.

Common situations: Environment mismatch: api_key issued for the live account used with environment: "demo" or vice versa; Trading212 API version bump moving paths under /v0; equities API enabled but the specific history endpoint not enabled for the key; broker-side maintenance windows.

Related errors


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/d27c1b64007cc7ca. Report an issue: GitHub.