What is the API endpoint for buying items in the catalog?

Hey! I am currently developping a tool for the roblox website that involves purchasing items. I went through most of the api endpoints, and I couldn’t find one that would allow me to purchase items on the catalog through an HTTP post request. The closest one I found to what I needed is https://catalog.roblox.com/docs#!/Bundle/post_v1_bundles_bundleId_unpack . Could anyone could tell me what the endpoint is (if it even exists)?

Thank you

3 Likes

You should use the web-browser debugging tools to figure out web APIs like this.

I have a project that does what you’re after.

The API is this:

https://economy.roblox.com/v1/purchases/products/<productId>

To use it, you first need to send a GET request for a catalog item page. The Classic Swordpack for example:

GET https://www.roblox.com/catalog/106690045

You then need to extract a bunch of information from it:

  • The XSRF token
  • The product ID (different from an asset ID)
  • The price

I leave it up to you to find out where these things are located in the HTML.

You also need your ROBLOSECURITY cookie to authenticate yourself.

Then you need to do a POST request.

POST https://economy.roblox.com/v1/purchases/products/15194787

X-CSRF-TOKEN: blah-token-blah
Content-Type: application/json; charset=utf-8
Cookie: .ROBLOSECURITY=ScaryTextThatsSensitive;

{"expectedCurrency":1,"expectedPrice":150,"expectedSellerId":1}

You should then check the response, (which is more JSON) to see whether it succeeded.

18 Likes

Thank you for your help. I appreciate it.

1 Like

I have a few more questions. Does the XSRF token change or always stay the same for an item?
Also, is expectedPrice is the price you want to purchase the item for?

I do not know whether the XSRF token changes. I just assumed it does and made my code grab it every time it processes a new request.

And yes, the expectedPrice is the price in Robux.

While I was making a discord bot, I noticed the token changes in less than 24 hours every time(I think) like Forbidden said, I recommend grabbing the token everytime you’re making a request

im trying with c# but me fail
returning 403

using (var client = new WebClient())
{
client.Headers[“X-CSRF-TOKEN”] = XCSRFToken;
client.Headers[“Cookie”] = “.ROBLOSECURITY=” + RBXSecurity + “;”;
//client.Headers[“Content-Type”] = “application/json; charset=utf-8”;

            NameValueCollection Values = new NameValueCollection
            {
                {"expectedCurrency", "1"},
                {"expectedPrice", "null"},
                {"expectedSellerId", "1"}
            };

            client.UploadValues("https://economy.roblox.com/v1/purchases/products/915193488","POST",Values);
        }
1 Like

For some reason, I get the error code 500 “Internal Server Error”

Here is my code:

  xsrfRequest = requests.post(authurl, cookies={ #GETTING XSRF TOKEN
                    '.ROBLOSECURITY': cookie
                })

                buyreq = requests.post( #BUYING THE ITEM
                    "https://economy.roblox.com/v1/purchases/products/" + str(productid),
                    cookies={'.ROBLOSECURITY': cookie}, data={"expectedCurrency": 1, "expectedPrice": seller['price'],
                                                              "expectedSellerId": seller['seller']['id']}, headers={
                        "X-CSRF-TOKEN": xsrfRequest.headers["x-csrf-token"],
                        "Content-Type": "application/json ; charset=utf-8"
                    }
                )


2 Likes

The endpoint works fine from what I’ve tested and I’ve written working code in both javascript (via node.js and the Axios http client installed via node’s package manager, npm) and python.

Both use different methods of retrieving the productId, expectedSellerId and expectedPrice because the first code I wrote here was the javascript one which uses this endpoint, which I couldn’t get to work in python so I had to go about it another way.

Javascript:

const cookie = .ROBLOSECURITY cookie goes here;
const axios = require('axios');
const ID = ID GOES HERE;

// function for grabbing X-CSRF-TOKEN

function GetToken(callback){
    let config = {
        url: "https://auth.roblox.com/v1/logout",
        method: "POST",
        headers: {
            "cookie": `.ROBLOSECURITY=${cookie}`
        }
    }

    let token;

    axios(config)
      .catch(res => {
          token = res.response.headers["x-csrf-token"];
          callback(token);
      })
};

// function for purchasing the item

function PurchaseItem(token){
    // Getting product info of the asset

    let config = {
        url: "https://catalog.roblox.com/v1/catalog/items/details",
        method: "POST",

        data: {
            "items": [
                {
                    "itemType": "Asset",
                    "id": ID
                }
            ]
        },

        headers: {
            "cookie": `.ROBLOSECURITY=${cookie}`,
            "x-csrf-token": token
        }

    }

    axios(config)
      .then(res => {
         let productId = res.data.data[0].productId;
         let name = res.data.data[0].name;

         let payload = {
             expectedSellerId: res.data.data[0].creatorTargetId,
             expectedCurrency: 1,
             expectedPrice: res.data.data[0].price
         };

         // this is where the asset is purchased

         let config = {
             url: `https://economy.roblox.com/v1/purchases/products/${productId}`,
             method: "POST",

             headers: {
                "cookie": `.ROBLOSECURITY=${cookie}`,
                "x-csrf-token": token
             },

             data: payload
         };

         axios(config)
           .then(res => console.log(`Successfully bought ${name}`))
           .catch(err => console.error(err))
      })
      .catch(err => console.error(err))
}

// buying the item

GetToken(
    (token) => {
        PurchaseItem(token)
    }
)

Python: @N43FGXL

import requests, json

# config

cookie = ""
assetId = 0

# getting token

auth_response = requests.post("https://auth.roblox.com/v1/logout", headers = {"cookie": f".ROBLOSECURITY={cookie}"})
token = None

if auth_response.status_code == 403:
    if "x-csrf-token" in auth_response.headers:
        token = auth_response.headers["x-csrf-token"]

headers = {
    "cookie": f".ROBLOSECURITY={cookie}",
    "x-csrf-token": token,
    "content-type": "application/json"
}

# getting asset details

payload = {
    "items": [
        {
            "itemType": 1,
            "id": assetId
        }
    ]
}

details = requests.post("https://catalog.roblox.com/v1/catalog/items/details", data = json.dumps(payload), headers = headers).json()
details = details["data"][0]
productId = details["productId"]

payload = {
    "expectedSellerId": details["creatorTargetId"],
    "expectedCurrency": 1,
    "expectedPrice": details["price"]
}

# buying item

buyres = requests.post(f"https://economy.roblox.com/v1/purchases/products/{productId}", headers = headers, data = json.dumps(payload))
print(buyres.json())

Edit (July 20th, 2023) - Updated python code to be working again

5 Likes

Does this work for the purchasing of limited items and ugc items?

Haven’t tested with limiteds and ugc. I solely tried this on library items, such as models and decals, but I’d imagine that buying items on the catalog uploaded by the Roblox account and ugc behave the same way.

For limiteds, probably. I’ve found that the expected price and expected seller id are the lowest selling price of the limited and the person selling it respectively. It would probably work for the python code, but the javascript code would take some editing.

If the python code doesn’t work for limiteds, well, it’d call for inspecting http requests via the debugging tools when you’re buying a limited

You cannot purchase limiteds with Python&Requests, you will only get error code 500’s, even with “params” and “data”.
Using the same values in JavaScript seems to get accepted, you will have to find a way around it.

Edit: I was wrong, you will have to use json.dumps() to stringify it and then Roblox will accept it.

Hey I am kind of late but is this still accurate? i was trying to buy a dev product and the request literally gives me status code 200 (ok) but nothing was actually purchased

What are you trying to achieve? What type of dev product are you buying?

I decided to try make a dynamic donation type thing in python after I discovered the endpoints to update dev products and finding out you can actually purchase items with api requests aswell.

I created a dev product in my roblox game and then tried to buy it, the buy request returned status code 200 and no errors but the purchase never happend and I cant figure out why

what module is that re could you send me it

The re module supports RegEx (Regular Expressions) which is a built-in module. You can just import it

Again, I’ve mentioned that the python code may work for limiteds because the expected price and expected seller Id both correspond with the least selling price of the limited and who is selling it. If it doesn’t, it may take some inspection of http requests via debugging tools

I appear to have an issue with my code, I copied yours and get this
“AttributeError: ‘NoneType’ object has no attribute ‘group’”
on

expectedPrice = int(re.search("data-expected-price=\"(\d+)\"", text).group(1))

I was wondering, what would be the best way to get the actual price of a limited item. ‘PriceInRobux’ only returns the initial listing price of the limited.

i want to get that information with code as well, how would i do that?

1 Like