Executando verificação de segurança...
3
XLR8
5 min de leitura ·

Mudanças na API da steam ocasiona problemas no mercado de skins de CSGO

Problema

Na quinta-feira (10/11/2022) a steam passou por uma atualização na antiga rota para listar itens de inventários: https://steamcommunity.com/profiles/<steamId>/inventory/json/730/2?l=brazilian. A rota passou a responder um objeto de erro e um status code 403, que representa um erro de proíbido, indicando que não temos permissão para acessar esse recurso.

Durante os dias 10 e 11 a atualização não tinha sido implementada corretamente e apesar de responder com status code 403, a resposta de erro estava concatenada com a resposta de sucesso, formando uma resposta json invalida com dois objetos concatenados, devido a isso era possível acessar as informações dos inventários mesmo com a resposta de erro. No entanto o erro não perdurou muito tempo e no dia 12 já não era possível mais utilizar essa trapaça.

NOTA!
Ainda é possível utilizar essa rota, porém será necessário estar autênticado no steamcommunity e apenas o inventário correspondente pode ser visualizado.

Status Code: 403 Forbidden

{
    "success": false,
    "Error": "Unsupported request"
}

Solução 1

Adicione os cookies de autênticação no formulário da request:

Steam_Language = english
timezoneOffset = 0,0
steamCountry = BR...
steamMachineAuth76642...XXX = A3...
steamLoginSecure = 76642...
sessionid = 32d37cc5abf001f8edc7b486

AVISO: Para obter as credênciais de acesso deverá ser realizado o login no steam community.

Status Code: 200 OK

{
  "success": true,
  "rgInventory": {
    "27342893808": {
      "id": "27342893808",
      "classid": "1239408100",
      "instanceid": "312003897",
      "amount": "1",
      "hide_in_china": 0,
      "pos": 1
    }
  },
  "rgCurrency": [],
  "rgDescriptions": {
    "1239408100_312003897": {
      "appid": "730",
      "classid": "1239408100",
      "instanceid": "312003897",
      "icon_url": "IzMF03bi9WpSBq-S-ekoE33L-iLqGFHVaU25ZzQNQcXdB2ozio1RrlIWFK3UfvMYB8UsvjiMXojflsZalyxSh31CIyHz2GZ-KuFpPsrTzBG0pe2BEHXlJjadf3HcTQswSrJbPD6IrTak5O6dQDjPRbklQVpSf_BR9zAfPsiNPRIjlNlc7Wa3m0tvEwMkZsxWfBbmyyIQZbxw7hyF-Lk",
      "icon_url_large": "IzMF03bi9WpSBq-S-ekoE33L-iLqGFHVaU25ZzQNQcXdB2ozio1RrlIWFK3UfvMYB8UsvjiMXojflsZalyxSh31CIyHz2GZ-KuFpPsrTzBG0pe2BEHXlVzvFPSbcUglrRLdXYGnd9mX3sbyUS23BQO0qFl0HL6oBo2cYb5-JOUY60NUL_Gf2h0p6WBUnfspUfRq33n0DPaR4yXcRccpXZsIUY5w",
      "icon_drag_url": "",
      "name": "Grafite Lacrado | Fica com o Troco (Verde grana)",
      "market_hash_name": "Sealed Graffiti | Keep the Change (Cash Green)",
      "market_name": "Grafite Lacrado | Fica com o Troco (Verde grana)",
      "name_color": "D2D2D2",
      "background_color": "",
      "type": "Grafite (Nível Básico)",
      "tradable": 1,
      "marketable": 1,
      "commodity": 1,
      "market_tradable_restriction": "7",
      "cache_expiration": "2022-11-23T02:13:32.999Z",
      "descriptions": [
        {
          "type": "html",
          "value": "Este é um padrão de grafite ainda lacrado. Ao abri-lo, você receberá cargas para grafitar este padrão <b>50<\/b> vezes no mundo do jogo."
        },
        {
          "type": "html",
          "value": " "
        },
        {
          "type": "html",
          "value": "",
          "color": "00a000",
          "app_data": {
            "limited": 1
          }
        }
      ],
      "owner_descriptions": "",
      "actions": [
        {
          "name": "Inspecionar no jogo...",
          "link": "steam:\/\/rungame\/730\/76561198085278322\/+csgo_econ_action_preview%20S%owner_steamid%A%assetid%D291242327383275146"
        }
      ],
      "market_actions": [
        {
          "name": "Inspecionar no jogo...",
          "link": "steam:\/\/rungame\/730\/76561198085278322\/+csgo_econ_action_preview%20M%listingid%A%assetid%D291242327383275146"
        }
      ],
      "tags": [
        {
          "internal_name": "CSGO_Type_Spray",
          "name": "Grafite",
          "category": "Type",
          "category_name": "Tipo"
        },
        {
          "internal_name": "normal",
          "name": "Normal",
          "category": "Quality",
          "category_name": "Categoria"
        },
        {
          "internal_name": "Rarity_Common",
          "name": "Nível Básico",
          "category": "Rarity",
          "color": "b0c3d9",
          "category_name": "Raridade"
        },
        {
          "internal_name": "Tint10",
          "name": "Verde grana",
          "category": "SprayColorCategory",
          "category_name": "Cor do grafite"
        }
      ]
    }
  },
  "more": false,
  "more_start": false
}

A responsta possui duas informações principais, uma é o rgInventory que corresponde aos assets do inventário, outra é o rgDescriptions que como o nome já diz, corresponde as descriptions do inventário.

Para encontrar a description relacionada a um asset, deve-se usar o classid e instanceid para formar a chave que acessa a description. Primeiro forma-se a chave concatenando os valores da seguinte forma: <classid>_<instanceid>, depois encontrar o valor usando a chave gerada como parâmetro no objeto rgDescriptions. Segue o exemplo abaixo:

if (!response.success)
        throw new Error(response.Error);

// Transforma o objeto rgInventory em uma matriz de chaves e valores.
// Cada elemento corresponde a um array com 2 indices sendo: [chave, valor]
const inventoryEntries = Object.entries(response.rgInventory);

for (const entry of inventoryEntries) {
    // Seleciona o asset como segundo elemento do array
    const value = entry[1];
    // Seleciona a description usando o classid e instanceid
    const description = response.rgDescriptions[`${value.classid}_${value.instanceid}`];

    if (!description) throw Error("Description not found");
    
    console.log(description) // Imprime a description encontrada.
}

Solução 2

A steam disponibilizou outra rota para listar inventários de terceiros que funciona sem a necessidade das credênciais de login.

Parâmetros

  • l: define a linguagem desejada na resposta. Ex.: (brazilian,english...)
  • count: define a quantidade máxima de assets listados, deve ser usado como paginação. (default=500)

https://steamcommunity.com/inventory/<steamId>/730/2?l=brazilian&count=2000

Status Code: 200 OK

{
  "assets": [
      {
          "appId": 730,
          "contextid": "2",
          "assetid": "12422068706",
          "classid": "1934302790",
          "instanceid": "301038000",
          "amount": "1"
      }
  ],
  "descriptions": [
      {
          "appid": 730,
          "classid": "1934302790",
          "instanceid": "301050380",
          "currency": 0,
          "background_color": "",
          "icon_url": "IzMF03bi9WpSBq...",
          "icon_url_large": "IzMF03bi9WpSBq...",
          "name": "Grafite Lacrado | Lambda (Verde grana)",
          "market_hash_name": "Sealed Graffiti | Lambda (Cash Green)",
          "market_name": "Grafite Lacrado | Lambda (Verde grana)",
          "name_color": "D2D2D2",
          "type": "Grafite (Nível Básico)",
          "tradable": 1,
          "marketable": 1,
          "commodity": 1,
          "market_tradable_restriction": 7,
          "descriptions": [
            {
              "type": "",
              "value": ""
            }
          ],
          "actions": [
            {
              "name": "Inspecionar no jogo...",
              "link": "steam://rungame/730/76561198085278322/+csgo_econ_action_preview%20S%owner_steamid%A%assetid%D10101232130337014500"
            }
          ],
          "market_actions": [
            {
              "name": "Inspecionar no jogo...",
              "link": "steam://rungame/730/76561198085278322/+csgo_econ_action_preview%20S%owner_steamid%A%assetid%D10101232130337014500"
            }
          ],
          "tags": [
            {
              "category": "Type",
              "internal_name": "CSGO_Type_Spray",
              "localized_category_name": "Tipo",
              "localized_tag_name":	"Grafite"
            },
            {
              "category": "Quality",
              "internal_name": "normal",
              "localized_category_name": "Categoria",
              "localized_tag_name":	"Normal"
            },
            {
              "category": "Rarity",
              "internal_name": "Rarity_Common",
              "localized_category_name": "Raridade",
              "localized_tag_name":	"Nível Básico",
              "color": "b0c3d9"
            },
            {
              "category": "SprayColorCategory",
              "internal_name": "Tint10",
              "localized_category_name": "Cor do grafite",
              "localized_tag_name":	"Verde grana"
            }
          ]
      }
  ],
  "success": 1,
  "total_inventory_count": 1
}

Dois avisos importantes!

  1. Os assets representam o item do inventário individualmente e as descriptions representam as particularidades daquele item. Um asset pode ser vinculado a um description quando tiverem o mesmo classid, ou seja, vários assets podem possuir um mesmo description baseado no classid.
  2. Nota-se que diferente da primeira request, essa rota não traz o campo cache_expirarion referente ao tradelock da skin. Para buscar o tradelock deve ser usado a primeira request juntamente com as credênciais de acesso.

Conclusão

Uma mudança minima da API da steam provocou reações diversas no mercado de skins e obrigou empresas a rever suas estratégias de negócio. Algumas empresas foram mais afetadas que outras, principalmente as que precisam acessar informações dos inventários de clientes para realizar negociações ou vendas, outros problemas comuns são falta de estoque, falha para criar trades podem ocorrer como consequência dessa mudança. Qualquer negócio no qual necessita verificar o tradelock de skins sofre com essa alteração devido a dificuldade de fazer essa validação.

NOTA: A steam também modificou os critérios de banimentos que ocasionou em uma maior incidência de 429 Too Many Requests. Se você tiver problemas com isso, experimente diminuir o intervalo entre suas requests e utilizar proxies para ip's.

Carregando publicação patrocinada...