Skip to main content

A Python Module for interacting with Portals Marketplace API

Project description

pypi stars Me Updates & Devs chat

Portals Marketplace API

This is a simple module for interacting with Portals API.

Huge thanks to boostNT for his code sample of getting authData

Join our devs chat!

Installation

pip install portalsmp

Change log

Version 1.0

  • First Beta release of the module. Working on most of the functions and bug fixes. Send your feedback to my telegram

Version 1.0.1

  • Removed owner_id from buy() function and PortalsGift class
  • makeOffer() should be fixed now.

Version 1.1

  • Added functions for working with offers: myPlacedOffers(), myReceivedOffers(), myCollectionOffers(), collectionOffer(), cancelCollectionOffer()
  • More in updated documentation

Version 1.1.1

  • Added topOffer() function

Version 1.1.2

  • Added list support for marketActivity() function (activityType=str|list)

Version 1.1.3

  • cancelOffer() should work now
  • Returned topOffer() function.

Version 1.1.4

  • Fixed marketActivity() function

Version 1.2

  • Offers: added editOffer(), allCollectionOffers() functions
  • Misc: added filterFloors() function
  • Switched from pyrogram to kurigram in dependencies, also removed pycryptodome from there.

Getting started (authData)

Unlike Tonnel Marketplace, every request in Portals needs to be authenticated.

The authentication system is also more complicated. There are currently 2 ways to get authData for Portals:

Telegram Web
  • Pros: easy, doesn't require Telegram login.
  • Cons: authData from Telegram Web is likely to have limited time (i think its around 1-7 days), so you will need to complete all the steps over and over
  1. Go to web.telegram.org
  2. Find @portals bot
  3. Open developer console -> Network tab
  4. Open @portals mini app
  5. Find any request related to portals-market.com (Network tab)
  6. Look for "Authorization" in request headers. It must look like this: "tma (auth)". Copy it entirely with "tma" at the start.
update_auth()
  • Pros: you don't need to waste your time on web.telegram.org; if auth token is expired - its not a big problem, simply use update_auth() again
  • Cons: api_id, api_hash and Telegram login needed. Pyrogram used.

Make sure to have latest version of pyrogram and tgcrypto before using

  1. Go to my.telegram.org/auth and create app
  2. Copy your api_id and api_hash
  3. Get your authData like this: token = asyncio.run(update_auth(api_id, api_hash))
  4. Use it in your code

Some examples

search(gift_name="toy bear", model="wizard", limit=10, authData=token)
[
  {
    "id": "65c83c42-0ab7-42cc-a46d-6158057a7216",
    "tg_id": "294992",
    "collection_id": "060d4cef-3a21-47e6-98fc-cd338ae0b5e0",
    "external_collection_number": 41771,
    "owner_id": 488711606,
    "name": "Toy Bear",
    "photo_url": "https://nft.fragment.com/gift/toybear-41771.large.jpg",
    "price": "44",
    "attributes": [
      {
        "type": "model",
        "value": "Wizard",
        "rarity_per_mille": 1.5
      },
      {
        "type": "symbol",
        "value": "Champagne",
        "rarity_per_mille": 0.2
      },
      {
        "type": "backdrop",
        "value": "Silver Blue",
        "rarity_per_mille": 2
      }
    ],
    "listed_at": "2025-06-12T16:28:05.550053Z",
    "status": "listed",
    "animation_url": "https://nft.fragment.com/gift/toybear-41771.lottie.json",
    "emoji_id": "5289667857599197149",
    "has_animation": true,
    "floor_price": "31.43",
    "unlocks_at": "2025-03-10T11:04:26Z"
  },...

Can be wrapped using PortalsGift class

gift = PortalsGift(search(gift_name="toy bear", model="wizard", limit=10, authData=token)[0])

gift.id - Portals ID of the gift

gift.tg_id - Telegram ID of the gift (external_collection_number)

gift.collection_id - Portals ID of the gift collection

gift.owner_id - ID of the gift owner

gift.name - Name of the gift

gift.photo_url - Photo URL of the gift (model + bg + symbol preview)

gift.price - Price of the gift

gift.model - Model name of the gift

gift.model_rarity - Model rarity of the gift

gift.symbol - Symbol of the gift

gift.symbol_rarity - Symbol rarity of the gift

gift.backdrop - Backdrop of the gift

gift.backdrop_rarity - Backdrop rarity of the gift

gift.listed_at - Time the gift was listed

gift.status - (usually listed)

gift.animation_url - Lottie animation URL of the gift

gift.emoji_id - Telegram custom emoji ID of the gift

gift.floor_price - Floor price of the gift (not the model)

gift.unlocks_at - Time of when the gift will be available to be minted


Functionality

search()

search(sort: str="price_asc", offset: int=0, limit: int=20, gift_name: str|list="", model: str|list="", backdrop: str|list="", symbol: str|list="", min_price: int=0, max_price: int=100000, authData: str="")
  • Search for gifts with any filters.
  • Available sorts: "price_asc", "price_desc", "latest", "gift_id_asc", "gift_id_desc", "model_rarity_asc", "model_rarity_desc"
  • offset is a "page", but a little bit different. Basically you need to multiply your limit by a page you want to get.
  • Also now available to pass a list of gift names / models etc!

giftsFloors()

giftsFloors(authData: str="") -> dict
  • Returns floors for all the gifts (short names only)

filterFloors()

filterFloors(gift_name: str = "", authData: str = "") -> dict
  • Returns a dict of floors of all models/backdrops/symbols for specified gift collection
  • Usage: filterFloors(gift_name="toy bear", authData="...")["models"] - will return all models of Toy Bear gift collection with floors etc.

myPortalsGifts()

myPortalsGifts(offset: int=0, limit: int=20, listed: bool=True, authData: str="") -> list
  • Returns a list containing your owned gifts.
  • listed=True for listed gifts, listed=False for unlisted gifts.

myPoints()

myPoints(authData: str="") -> dict
  • Returns information about your Portals points.

myBalances()

myBalances(authdata: str="") -> dict
  • Returns information about your balances.

myActivity()

myActivity(offset: int=0, limit: int=20, authData: str="") -> list
  • Returns a list object with all your activities on the market.

collections()

collections(limit: int=100, authData: str="") -> list
  • Returns a list object with all collection names, floors, daily volumes etc.

marketActivity()

marketActivity(sort: str="latest", offset: int=0, limit: int=20, activityType: str="", gift_name: str|list="", model: str|list="", backdrop: str|list="", symbol: str|list="", min_price: int=0, max_price: int=100000, authData: str="") -> list
  • Like saleHistory() in tonnelmp
  • Activity types: "", "buy", "listing", "price_update", "offer"
  • Available sorts: "price_asc", "price_desc", "latest", "gift_id_asc", "gift_id_desc", "model_rarity_asc", "model_rarity_desc"

sale()

sale(nft_id: str="", price: int|float=0,authData: str="") -> dict|None
  • List a single nft for sale

bulkList()

bulkList(nfts: list= [], authData: str="") -> dict
  • List multiple nfts for sale
  • Not tested yet

buy()

buy(nft_id: str="", owner_id: int=0, price: int|float=0, authData: str="") -> dict|None
  • Buy a single nft
  • Will add bulkBuy soon

makeOffer()

makeOffer(nft_id: str="", offer_price: float=0, expiration_days: int=7, authData: str="") -> dict|None
  • Make offer for nft
  • expiration_days: either 0 or 7. 0 means no expiration, 7 - 7 days.

cancelOffer()

cancelOffer(offer_id: str="", authData: str="") -> dict|None
  • Cancel offer with known offer_id

editOffer()

editOffer(offer_id: str = "", new_price: float = 0, authData: str = "") -> None
  • Edit the price of the offer with known offer_id

collectionOffer()

collectionOffer(gift_name: str = "", amount: float | int = 0, expiration_days: int = 7, max_nfts: int = 1, authData: str = "")
  • Make offer for collection

cancelCollectionOffer()

cancelCollectionOffer(offer_id: str = "", authData: str = "")
  • Cancel collection offer with known offer_id

allCollectionOffers()

allCollectionOffers(gift_name: str = "", authData: str = "") -> list
  • Returns a list of dicts with all collection offers for the specified gift collection (gift_name)

topOffer()

topOffer(gift_name: str = "", authData: str = "")
  • Returns top offer for specified gift collection

myPlacedOffers()

myPlacedOffers(offset: int = 0, limit: int = 20, authData: str = "")
  • Returns a list of dicts with your placed offers

myReceivedOffers()

myReceivedOffers(offset: int = 0, limit: int = 20, authData: str = "")
  • Returns a list of dicts with offers you have received on your gifts

myCollectionOffers()

myCollectionOffers(authData: str = "")
  • Returns a list of dicts with collection offers you have made

changePrice()

changePrice(nft_id: str="", price: float=0, authData: str="") -> dict|None
  • Change price of the listed nft

withdrawPortals()

withdrawPortals(amount: float=0, wallet: str="", authData: str="") -> dict
  • Withdraw from portals to your TON wallet
  • Warning: pass UQ addresses at your own risk. May work only with EQ addresses.

Info

currently working on detailed documentation + remaining functions + bug fixes

my telegram: t.me/perfectlystill

chat: t.me/giftsdevschat

donations:

  • ton: UQC9f1mTuu2hKuBP_0soC5RVkq2mLp8uiPBBhn69vadU7h8W

made with ❤️ by bleach

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

portalsmp-1.2.tar.gz (17.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

portalsmp-1.2-py3-none-any.whl (14.1 kB view details)

Uploaded Python 3

File details

Details for the file portalsmp-1.2.tar.gz.

File metadata

  • Download URL: portalsmp-1.2.tar.gz
  • Upload date:
  • Size: 17.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.2

File hashes

Hashes for portalsmp-1.2.tar.gz
Algorithm Hash digest
SHA256 18e744a3740c2b002b31984c04b5daa3d44bd5eb3f6af801c68fb80552497ed1
MD5 ccf2180f7db8057bbbca68e34e8eaaaf
BLAKE2b-256 57cde5591b2e48bb0dae94191263e485204717121667e2233d01faefffa14f9d

See more details on using hashes here.

File details

Details for the file portalsmp-1.2-py3-none-any.whl.

File metadata

  • Download URL: portalsmp-1.2-py3-none-any.whl
  • Upload date:
  • Size: 14.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.2

File hashes

Hashes for portalsmp-1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 056c24e9113c77c79239d50511512c539c78f3f075b5590f5b6847dd885f3b2c
MD5 8ed80a5ed6c6f52e4a57ed94e38ad317
BLAKE2b-256 d2c1438c2c9e528be7ba5571ac422af59fa0645bb0432f09b87873757ca9f9f6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page