Skip to main content

faportalsmp

Asynchronous Python library for the Portals Gift Marketplace API.

A maintained fork of aportalsmp — trade Telegram gifts (NFTs), place and manage offers, run giveaways, read your account, and deposit & withdraw GRAM.

pip install faportalsmp

Imported as aportalsmp:

import aportalsmp as portals

Quick start

import asyncio
import aportalsmp as portals

AUTH = "tma query_id=...&user=...&auth_date=...&hash=..."  # see Authentication

async def main():
    floors = await portals.giftsFloors(authData=AUTH)
    print("Plush Pepe floor:", floors.floor("plushpepe"))

    listings = await portals.search(gift_name="Plush Pepe", sort="price_asc", limit=5, authData=AUTH)
    for gift in listings:
        print(gift.name, gift.model, gift.price)

    balances = await portals.myBalances(authData=AUTH)
    print("Balance:", balances.balance, "GRAM")

asyncio.run(main())

Authentication

Every request needs authData — a Telegram Mini App initData string prefixed with tma . Generate it from a Telegram user session with update_auth():

from aportalsmp import update_auth

# with api_id / api_hash (creates a .session file)
authData = await update_auth(api_id=12345, api_hash="abc...", session_name="account")

# or from an existing Pyrogram/Kurigram session string
authData = await update_auth(session_string="BQ...")

Wallet — GRAM deposits & withdrawals

GRAM is the native coin (moved on the TON network). Amounts and balances are in GRAM; addresses and the on-chain transfer use the TON network.

Balance, limits & history

bal    = await portals.myBalances(authData=AUTH)     # .balance, .frozen_funds
limits = await portals.walletLimits(authData=AUTH)   # .min_deposit, .min_withdraw, .max_withdraw, .daily_limit
hist   = await portals.walletHistory(offset=0, limit=20, authData=AUTH)

Deposit GRAM

A deposit is a native GRAM transfer to the Portals deposit wallet carrying a text comment equal to the deposit id — that's how the marketplace credits your balance.

Intent — send it yourself (from any wallet/bot):

info = await portals.deposit(authData=AUTH)
print(info.address)   # where to send GRAM
print(info.comment)   # text comment to attach (the deposit id)
print(info.amount)    # expected amount, if provided

Auto-send — the library signs & broadcasts for you (needs a wallet mnemonic):

info = await portals.deposit(
    amount=0.5,
    mnemonic="word1 word2 ... word24",   # used only to sign, never transmitted
    wallet_version="v4r2",                # v4r2 (default), v3r2, v3r1, v5r1
    authData=AUTH,
)
print(info.sent_tx)   # {'status': 'sent', 'amount': 0.5, 'to': ..., 'comment': ...}

statuses = await portals.depositStatus(ids=info.id, authData=AUTH)

Withdraw GRAM

withdrawal_id = await portals.withdrawGram(amount=1.0, wallet="UQ...external_address", authData=AUTH)
statuses = await portals.withdrawStatus(ids=withdrawal_id, authData=AUTH)

withdrawPortals and withdrawTon are kept as aliases of withdrawGram.


Gifts

Function Purpose
giftsFloors(authData) Floor prices for every collection (by short name)
filterFloors(gift_name, authData) Model / backdrop / symbol floors for a collection
collections(limit, authData) Collections with floor, supply, volume
search(...) Search listings with filters & sorting
marketActivity(...) Recent buys / listings / offers / price updates
myPortalsGifts(offset, limit, listed, authData) Your owned gifts
myActivity(offset, limit, authData) Your activity
buy(nft_id, price, authData) Buy a listing
sale(nft_id, price, authData) / bulkList(nfts, authData) List gift(s) for sale
changePrice(nft_id, price, authData) Re-price a listing
transferGifts(nft_ids, username, anonymous, authData) Transfer gifts to a user
withdrawGifts(nft_ids, authData) Withdraw gifts out of the marketplace
getGiveaways / giveawayInfo / joinGiveaway Giveaways
gifts = await portals.search(
    gift_name="Plush Pepe",
    model="Sad Cat",
    backdrop=["Onyx Black", "Midnight Blue"],
    sort="price_asc", min_price=0, max_price=5000, limit=20,
    authData=AUTH,
)
if gifts:
    result = await portals.buy(nft_id=gifts[0].id, price=gifts[0].price, authData=AUTH)

Gift names resolve leniently — "plush pepe", "Durov's Cap" and "Durov’s Cap" all work.


Your gifts & inventory

See everything you own, then unlist, quick-sell, transfer or withdraw it.

# full inventory — everything you own (listed or not)
mine = await portals.inventory(offset=0, limit=50, authData=AUTH)
for g in mine:
    print(g.name, g.model, g.status)

groups = await portals.inventoryCollections(authData=AUTH)   # grouped by collection, with counts
value  = await portals.inventoryValue(authData=AUTH)          # estimated inventory value (GRAM)

# only your marketplace listings
listed = await portals.myPortalsGifts(listed=True, authData=AUTH)

# take a gift off sale
await portals.unlist(nft_id=mine[0].id, authData=AUTH)              # or bulkUnlist(nft_ids=[...])

# instant-sell into the best collection offer
await portals.quickSalePreview(nft_ids=[mine[0].id], authData=AUTH)  # preview payout
await portals.quickSale(nft_ids=[mine[0].id], authData=AUTH)

# withdraw the gift out of Portals (to your Telegram account)
await portals.withdrawGifts(nft_ids=[mine[0].id], authData=AUTH)

# or transfer it to another Portals user
await portals.transferGifts(nft_ids=[mine[0].id], username="someone", authData=AUTH)

# check gifts are still available before buying
await portals.checkAvailability(nft_ids=[some_id], authData=AUTH)
Function Purpose
inventory(offset, limit, authData) Every gift you own (listed or not)
inventoryCollections(authData) Inventory grouped by collection, with counts
inventoryValue(authData) Estimated total inventory value (GRAM)
myPortalsGifts(offset, limit, listed, authData) Your gifts by marketplace listing status
unlist(nft_id, authData) / bulkUnlist(nft_ids, authData) Remove gift(s) from sale
quickSalePreview / quickSale(nft_ids, authData) Preview & instant-sell into the top offer
checkAvailability(nft_ids, authData) Check gifts are still available
withdrawGifts(nft_ids, authData) Withdraw gifts out of Portals (to Telegram)
transferGifts(nft_ids, username, anonymous, authData) Transfer gifts to another user

Offers

await portals.makeOffer(nft_id="...", offer_price=10, expiration_days=7, authData=AUTH)
await portals.editOffer(offer_id="...", new_price=12, authData=AUTH)
await portals.cancelOffer(offer_id="...", authData=AUTH)

await portals.collectionOffer(gift_name="Plush Pepe", amount=100, max_nfts=3, authData=AUTH)
top = await portals.topOffer(gift_name="Plush Pepe", authData=AUTH)

received = await portals.myReceivedOffers(authData=AUTH)
placed   = await portals.myPlacedOffers(authData=AUTH)

Advanced trading

Granular floors, market config, portfolio history and premarket orders (these return raw API dicts):

await portals.backdropFloors(gift_name="Plush Pepe", authData=AUTH)
await portals.modelBackgroundFloors(gift_name="Plush Pepe", authData=AUTH)
await portals.attributeFloors(payload={...}, authData=AUTH)
await portals.marketConfig(authData=AUTH)
await portals.inventoryCostHistory(authData=AUTH)

# premarket (collateral-based; POST bodies are marketplace-defined)
await portals.premarketCollaterals(authData=AUTH)
await portals.premarketCollections(authData=AUTH)
await portals.premarketPreviewGift(payload={...}, authData=AUTH)
await portals.premarketAddGift(payload={...}, authData=AUTH)

Referrals & cashback

# referrals
await portals.referralInfo(authData=AUTH)
await portals.referralFriends(offset=0, limit=20, authData=AUTH)
await portals.referralLevels(authData=AUTH)
await portals.applyReferral(code="FRIEND_CODE", authData=AUTH)
await portals.claimReferral(authData=AUTH)

# cashback
await portals.cashbackInfo(authData=AUTH)
await portals.cashbackLevels(authData=AUTH)
await portals.claimCashback(authData=AUTH)

Keeping the gift list fresh

Collection IDs live in aportalsmp/utils/collections_ids.py and are generated from the public /collections endpoint. When new gifts drop, regenerate them:

python scripts/update_collections.py

Data objects

Every response is wrapped in a lightweight object with typed properties and a .toDict() escape hatch:

PortalsGift, CollectionOffer, GiftOffer, Points, Stats, Balances, DepositInfo, DepositStatus, WithdrawStatus, WalletLimits, WalletHistory, Filters, GiftsFloors, Collections, Activity, MyActivity, SaleResult, Giveaway, GiveawayRequirements, …


Errors

All errors subclass Exception and live in aportalsmp:

authDataError, offerError, accountError, requestError, connectionError, floorsError, giftsError, tradingError.

from aportalsmp import requestError

try:
    await portals.buy(nft_id="...", price=1.0, authData=AUTH)
except requestError as e:
    print("API error:", e)

Disclaimer

Unofficial library — not affiliated with Portals. Trading and GRAM transfers move real assets; test with small amounts first and keep your mnemonics safe. Use at your own risk.

Metadata

Release files for faportalsmp 2.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for faportalsmp 2.2.0
File Size Uploaded
faportalsmp-2.2.0.tar.gz 36.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for faportalsmp 2.2.0
File Interpreter ABI Platform
faportalsmp-2.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 69.7 kB

Release files / faportalsmp-2.2.0.tar.gz

Download URL faportalsmp-2.2.0.tar.gz
Size 36.6 kB
Tags Source
SHA-256 checksum
How to use checksums
f58c7e6cdf7c8493d6139fb7d73bb37bd542ccaa3bbc37e7c416e0faad4623d6
BLAKE2b-256 checksum
How to use checksums
bfd8dc9f161c1cb9acd74d0b544df3c82dc335d32b77a6b073b5c6dff797d3c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / faportalsmp-2.2.0-py3-none-any.whl

Download URL faportalsmp-2.2.0-py3-none-any.whl
Size 33.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c7e512bccbc52f41ae1026c23d88797f6bce54b7579ee437c3ae24095aa308a9
BLAKE2b-256 checksum
How to use checksums
aacd82e721635ed379eb6d1c5a9e218c251e1c421672b61f82d66594ba15167c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release history Release notifications | RSS feed

This release

2.2.0 This release

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page