SDK
Getting started
Overview
@fazedotfun/sdk is the official TypeScript client for Faze. It wraps the same platform API the web app runs on: coin lists and summaries, metrics, holders, trade tapes, candles, the activity feed, launches, wallet holdings and PnL, profiles, and world and ad data - plus non-custodial trade and launch building.
- Typed and validated. Every response is parsed at runtime against the same schemas the platform uses, so a drifted server response throws instead of silently mistyping.
- Non-custodial by construction. Nothing in the SDK touches a private key. Build calls return transaction requests; your own wallet signs and broadcasts them.
- No account needed for reads. Every public read endpoint works without a key, an API token, or a session.
- ESM-only, dependency-light, and runs in the browser and in Node alike.
The contracts remain the source of truth
Install and quickstart
npm install @fazedotfun/sdk
# only if you build or sign transactions yourself (the /chain entry)
npm install viemThe package is on the public npm registry as @fazedotfun/sdk, MIT licensed. It is ESM-only and its one runtime dependency is zod. viem is an OPTIONAL peer: install it only for the /chain entry below, which builds and signs transactions - the rest of the client does not import it.
import { createClient } from '@fazedotfun/sdk';
// baseUrl is the platform API origin plus the /api/v1 version prefix.
const client = createClient({ baseUrl: 'https://faze.fun/api/v1' });
const config = await client.getLaunchConfig(); // live fee rates + chain profile
const coins = await client.listCoins(); // the public launch feedPoint baseUrl at the platform API origin including the /api/v1 version prefix - on this deployment, the origin serving this page (https://faze.fun/api/v1). That is the whole setup for public data - reads work immediately, no key and no session.
Client options
createClient takes a single options object. The surface is deliberately small:
| baseUrl | API origin + version prefix, e.g. https://faze.fun/api/v1 (required) |
|---|---|
| fetch | custom fetch implementation, e.g. a cookie-jar-aware one for server-side sessions |
| headers | headers merged into every request - how a non-browser consumer carries its session |
The transport is deliberately thin - no response cache, no automatic retries, no hidden state. A published client cannot know its consumer's freshness or retry needs, and a cache it cannot invalidate is a correctness hazard; put caching in your own layer (react-query, a CDN, a worker), where invalidation lives. Rate limits surface as a typed error carrying the server's schedule (see Errors and rate limits).
Guides
Sessions and wallet linking
There are two access levels. Public reads need nothing. Wallet-scoped verbs - buildLaunch, getWatchlist, setCoinSentiment, the profile writes - act on a session with a linked wallet. Sessions ride a signed cookie the API mints on your first request: in a browser it round-trips automatically (the SDK sends credentials: 'include'). A server-side consumer has no cookie jar, so pass a cookie-jar-aware fetch - or forward the session cookie yourself via headers.
Linking proves wallet ownership with a signature over a single-use challenge - no transaction, no gas:
// 1. The terms version this deployment enforces. Linking without it is a 403, so read it
// rather than hardcoding it - it changes when the terms do.
const { termsVersion } = await client.getLaunchConfig();
// 2. Ask for the challenge - a single-use, short-lived message bound to your session.
const challenge = await client.walletChallenge();
// 3. Sign it with the wallet (EIP-191 personal_sign; viem shown here).
const signature = await wallet.signMessage({ message: challenge.message });
// 4. Complete the link. Wallet-scoped calls now act as this wallet.
await client.walletLink({ publicKey: address, signature, acceptedTermsVersion: termsVersion });The challenge is session-bound and short-lived, and a failed attempt burns it - just request a fresh one. walletUnlink is the disconnect path: without it, a wallet switch leaves the old wallet as the session identity until a re-link happens.
acceptedTermsVersion is required
403 terms acceptance required, which gates every wallet-scoped verb. Read the value from getLaunchConfig().termsVersion rather than hardcoding it: it changes when the terms do, and every stored acceptance expires with it. The 403 body carries the current termsVersion too, so a client can recover from a bump without a redeploy.Trading
Trading does not go through the platform. The API's own quote and build routes are retired unless a deployment opts into paying chain RPC for each user, so the SDK does not publish them at all - the @fazedotfun/sdk/chain entry runs the same quoting and transaction-building against an endpoint you choose, and nothing about it can be switched off under you.
import { createTrader } from '@fazedotfun/sdk/chain';
// A key and an RPC endpoint of your choosing. Nothing here goes through the platform:
// it reads the deployment's contract addresses and the coin's row, and everything else -
// quoting, building, broadcasting, the receipt - runs against your endpoint.
const trader = createTrader({ client, privateKey, rpcUrl: 'https://your-own-rpc' });
// Read-only, safe to poll as the user types.
const quote = await trader.quote({ mint, side: 'buy', amountIn: 10_000_000_000_000_000n });
// Build, sign, broadcast and confirm. It picks the venue off the coin's lifecycle,
// sends the requests in order (a sell prepends an approve, and the swap waits for it),
// and serializes its own sends so one key's nonce sequence stays single-threaded.
const result = await trader.trade({ mint, side: 'buy', amountIn: 10_000_000_000_000_000n });
result.status; // 'confirmed' | 'reverted' - a revert is the receipt's answer, not an error
result.hashes; // every hash broadcast, in order
One trader per key
buildCurveTrade yourself.Amounts are bigint base units: wei on a buy, coin units on a sell (trader.coinBalance(mint) reads the position). trader.quote is read-only and cheap - poll it as the user types and treat trader.trade as the commit point. If you sign elsewhere - a browser wallet, a remote signer, an HSM - take buildCurveTrade instead and broadcast its ordered list yourself, waiting for each receipt before the next.
The /chain entry, in full
createTrader is the assembled path; underneath it, the entry exports every piece it is built from, so a consumer that owns its own signing, batching or retry can use them directly.
| curveConfigFrom(contracts) | getLaunchConfig().curveContracts -> the CurveConfig everything else takes |
|---|---|
| createTrader(options) | the assembled path: quote, trade, coinBalance, with sends serialized per key |
| quoteCurveTrade(client, config, ref, input) | read-only quote: amount out, price impact, venue |
| buildCurveTrade(client, config, ref, input) | the ordered tx-requests to sign and broadcast yourself |
| readCurveCoinState(client, config, ref) | the coin's on-curve reserves and progress, read from the chain |
| coinBondingCurve(ref, config) | which curve address serves this coin (its generation is fixed at launch) |
| coinCurveKind(ref, config) | the coin's curve generation, 'v3' or 'v4' |
| applySlippageFloor(expectedOut, slippageBps) | the minimum-out a build should carry |
| ProtocolError | thrown for a refusal that is safe to show a user verbatim |
These take POSITIONAL arguments
(client, config, ref, input) in that order - a viem PublicClient, the CurveConfig from curveConfigFrom, the coin reference, then the operation's input. Passing one options object instead fails inside the call with Cannot read properties of undefined, which does not point at the mistake.import { createPublicClient, http } from 'viem';
import { curveConfigFrom, quoteCurveTrade, buildCurveTrade, applySlippageFloor } from '@fazedotfun/sdk/chain';
const client = createPublicClient({ transport: http('https://your-own-rpc') });
const config = curveConfigFrom((await sdk.getLaunchConfig()).curveContracts);
const ref = { mint, chain: launch.chain, providerMeta: launch.providerMeta };
// Positional, in this order - NOT one options object.
const quote = await quoteCurveTrade(client, config, ref, { side: 'buy', amountIn: 10_000_000_000_000_000n });
const built = await buildCurveTrade(client, config, ref, {
side: 'buy',
amountIn: 10_000_000_000_000_000n,
minAmountOut: applySlippageFloor(quote.amountOut, 100), // 1%
from: address,
});
// built.txRequests: sign and broadcast in order, waiting for each receipt before the next.Launching a coin
buildLaunch does the whole preparation in one call: the API predicts the coin's CREATE2 address, writes the registry row, generates the metadata, and builds the create transaction against its own RPC. Your wallet signs and broadcasts; the server signs nothing and never holds a key. It requires a live session with a wallet linked on the target chain, and spends a tight rate-limit bucket.
const build = await client.buildLaunch({ ticker: 'DEMO', name: 'Demo Coin' });
// The coin address is CREATE2-predicted, so it is known before anything is broadcast.
const mint = build.launch.mint;
// Sign and broadcast build.txRequests in order, waiting for each receipt before the next
// (an ERC-20 dev buy prepends approve; a launch-time burn commitment - burnShareBps - appends
// the factory's clone deploy, which also seats the clone as the coin's creator on the curve,
// so that launch signs TWO and the burn is locked from the block the deploy lands).
// The create is build.txRequests[build.launchTxIndex ?? build.txRequests.length - 1];
// report ITS hash - the platform's on-chain verifier owns the lifecycle from here, and
// getLaunch(mint) reflects each state change.
const launchHash = hashes[build.launchTxIndex ?? build.txRequests.length - 1];
await client.confirmLaunch(mint, { signature: launchHash });Optional request fields cover a custom bonding target, an atomic dev buy that executes inside the launch transaction at the curve floor, a gated launch that stays dormant until the creator's first buy, an irreversible creator fee burn, and website and social links for the coin's metadata. Each is validated server-side against the chain profile's bounds.
Pagination and data conventions
Conventions that hold across the whole read surface:
- Cursors are opaque and sort-bound. Keyset-paginated lists (
listCoins,listLaunches,getCoinTraders) return anextCursoryou pass back verbatim. Never construct one, and never reuse one across a re-sort - that is a 400. - Tapes page backwards by time. Trade feeds take
before= the last row'stimeMs. Candles come oldest-first, so a chart appends and pages older withbefore= the first candle'sbucketStartMs. - Amounts are base-unit decimal strings. Convert with
BigInt, never floating point. - USD fields are nullable. A null means the platform itself has no fresh rate - render a dash, never $0. Convert only with
getNativeUsdRatesso your figures agree with the rows the platform computed from exactly that rate. - Figures are ingest-era truth. Trader stats and realized PnL are folded from the trades the indexer has seen, so they understate rather than invent - see each method's notes in the reference.
- Bad input is refused, not answered. A wallet argument that is not an address is a 400 rather than an empty portfolio, an unknown mint is a 404 on every per-coin read, and a patch naming a field that does not exist is a 400 rather than a 200 that changed nothing.
- Usernames are 3-14 characters of
[A-Za-z0-9_], stored lowercase and unique.checkHandleis the pre-flight for both validity and availability - itsreasondistinguishesinvalidfromreservedandtaken- but it is advisory: the uniqueness index at save time is the arbiter, so still handle409 username taken.
Errors and rate limits
The SDK throws two typed errors. ApiError covers any non-ok response and carries the HTTP status plus apiError, the API's stable error identifier - branch on those, never on message text. On a 400 from schema validation it also carries details, an array of {field, reason} naming which field was refused and why, so you can point at the offending input instead of re-reading the body yourself. RateLimitError is thrown on 429 specifically and carries the server's own schedule: retryAfterMs, limit, remaining, and resetAt.
import { ApiError, RateLimitError } from '@fazedotfun/sdk';
try {
await client.updateProfile({ username: 'robin' });
} catch (error) {
if (error instanceof RateLimitError) {
// Resume on the server's schedule, never a guess.
await new Promise((resolve) => setTimeout(resolve, error.retryAfterMs));
} else if (error instanceof ApiError && error.status === 409) {
// error.apiError carries the API's stable identifier - branch on it, not message text.
} else if (error instanceof ApiError && error.status === 400) {
// A schema refusal names the field: [{ field: 'username', reason: 'letters, digits and underscore only' }]
for (const { field, reason } of error.details ?? []) console.error(field, reason);
}
}Public reads share a lenient bucket and wallet-scoped verbs a tighter one, with buildLaunch the tightest of all. A well-behaved integration backs off on retryAfterMs and caps its polling loops. Note that none of the rate limits touch trading: quotes, builds, balances and receipts run on your own RPC, so the only limit they meet is your endpoint's.
Versioning and stability
Pin an exact version
The method reference below is generated from the published package's source, so it cannot drift from the shipped client. For a trust-minimized integration with no dependency on our servers at all, the on-chain contracts documented on the protocol documentation page remain the stable interface.
Method reference
Market and launch reads
| Method | Description |
|---|---|
health health(): Promise<Health> | Probe the API's health. |
listCoins listCoins(query?: CoinListQuery): Promise<CoinList> | The coin discovery list: the sorted, filtered coin feed. Every field of `query` is optional; an absent one is OMITTED from the wire (the API refuses a present-but-empty param), `states`/`keywords`/`links` serialize as CSV, and `limit` is clamped into the API's accepted range. Keyset-paginated: pass `nextCursor` back verbatim as `query.cursor`. The cursor is OPAQUE and bound to `(sort, window, dir)` - never build one, and never reuse one across a re-sort, which is a 400. USD row fields are nullable when the rate feed is down: show "-", not $0. |
getCoinSummary getCoinSummary(mint: string): Promise<CoinSummaryView> | One coin's registry record plus its metrics snapshot in a single read, so a coin page renders in one trip. |
getCoinMetrics getCoinMetrics(mint: string): Promise<CoinMetricsView> | A coin's market-metrics snapshot: price and valuation, the m5/h1/h6/h24 windows, holder stats, fees, ATH, and the graduation record once migrated. Freshness is the indexer's rollup cadence - `computedAtMs` says how fresh. |
getCoinHolders getCoinHolders(mint: string, parameters?: { limit?: number; cursor?: string; }): Promise<CoinHoldersView> | A coin's holder surface: live holder count plus top holders by balance. Venue addresses (curve, pool, burn) are excluded from the ranking and ride `venues` as labeled rows instead. |
getCoinTraders getCoinTraders(mint: string, query?: CoinTradersQuery): Promise<CoinTradersList> | A coin's traders, ranked by `volume` (default), `realized-pnl`, `last-trade` or `buys`. Keyset-paginated by an OPAQUE cursor bound to (sort, dir), like `listCoins`. INGEST-ERA TRUTH: every figure is folded from the trades the indexer has SEEN, so a coin whose ingest began mid-life has traders whose earlier history is not counted. `realizedPnlNative` degrades further - a sell of tokens the ledger never saw bought has no basis to relieve, so it is skipped rather than booked as a gain, and that trader's realized figure UNDERSTATES what they made. `volume` needs no basis and stays honest, which is why it is the default sort. |
getCoinTrades getCoinTrades(mint: string, parameters?: { limit?: number; before?: number; }): Promise<CoinTradesView> | A coin's trade tape, newest first. `before` (epoch ms) pages older trades; the next cursor is the last row's `timeMs`. |
getCoinBurns getCoinBurns(mint: string, parameters?: { limit?: number; before?: number; }): Promise<CoinBurnsView> | A coin's fee-burn history, newest first: one row per firing of the creator's fee-burn conveyor (fees spent, coin sent to the dead address, who cranked it and their bounty, the tx). Empty for a coin without a burn commitment. `before` (block number) pages older burns; the next cursor is the last row's `blockRef`. The tip page also carries `graduationBurn` - the one-off token-tail burn at graduation - which is null on cursored pages and on a coin still on the curve. |
getCandles getCandles(mint: string, parameters?: { timeframe?: CandleTimeframeRequest; limit?: number; before?: number; }): Promise<CandleSeries> | A coin's candle series. `timeframe` is auto/1m/1h/4h/1d (`auto` picks a readable width from the coin's candle counts); the response's `timeframe` is always the CONCRETE width. Candles come oldest-first, so a chart appends and the next `before` is `candles[0].bucketStartMs`. |
getActivity getActivity(query?: ActivityQuery): Promise<ActivityFeedView> | The global recent-trades feed across every coin the deployment serves, newest first. Paged like the tapes (`before` = the last row's `timeMs`), and `chain` narrows the scope like `listCoins`. A TIP, NOT AN ARCHIVE: it reaches back 24h and reports that edge as `windowStartMs`, so a walk ENDS there by design rather than by running out of data - an empty page at the edge is not an error. For depth on one coin use `getCoinTrades`, which is indexed for it. |
getCoinSentiment getCoinSentiment(mint: string): Promise<CoinSentimentView> | A coin's community sentiment: the rocket/shit tallies plus THIS caller's own standing. Per-caller by construction, so never cache it across users. A disconnected caller gets the tallies with `canVote: false` and `myVote: null` - not an error, and not a reason to hide the counts. |
getPoolFee getPoolFee(mint: string): Promise<PoolFeeView> | A graduated coin's pool base fee, for a post-graduation status row. `baseFeeBps` is null while the coin has no pool yet (on the curve or mid-migration) - and also when the chain read failed, which the platform degrades to rather than failing an otherwise usable panel. It is a DISPLAY figure: what a trade actually pays is quoted. |
getLaunch getLaunch(mint: string): Promise<LaunchRecord> | One launch by its on-chain mint address. |
listLaunches listLaunches(parameters?: { cursor?: string; limit?: number; sort?: LaunchSort; state?: LaunchLifecycleState; world?: string; q?: string; }): Promise<LaunchList> | List launches, keyset-paginated by `cursor`. `sort` is `recency` (default) or `momentum`, and the cursor is sort-specific. `world` narrows to coins on that named world's home chain; an unknown world is a 404, because the server never widens past the chain-homing rail.
|
getLaunchConfig getLaunchConfig(): Promise<LaunchConfig> | The static launch config: the enabled chains, the default launch chain, the live owner-tunable fee knobs, and `curveContracts` - the deployment's effective contract addresses. It changes only on a redeploy or a knob change, so cache it aggressively. `curveContracts` is what this package's `/chain` builders take (via `curveConfigFrom`). Read the addresses from here rather than hardcoding them: a deployment can move a contract, and a stale address still builds a perfectly valid transaction - aimed at the wrong one. |
getPlacements getPlacements(): Promise<MapPlacementsSnapshot> | Every placed coin with the island shop it stands at, rank-ascending (1 = closest to the plaza). Unplaced coins are absent; find them through `listCoins`. |
getNativeUsdRates getNativeUsdRates(): Promise<NativeUsdRates> | The gas-token/USD rates the PLATFORM is using - one per native symbol the deployment serves. Convert NATIVE figures with these and no other oracle: a native coin's USD fields were computed from exactly this rate, so another source drifts against the rows on the same screen. A null `priceUsd` means the platform itself has no fresh rate - hide USD rather than substituting a zero. These rates do NOT apply to a coin raised in a quote asset (its `quoteAsset` is set): that coin's figures are in the quote asset's units and convert at `quoteAsset.unitPriceUsd`, never at the gas token's rate. |
Wallet reads
| Method | Description |
|---|---|
getWalletHoldings getWalletHoldings(wallet: string): Promise<WalletHoldingsView> | Every launchpad coin a wallet holds (balance > 0), largest worth first. Public by wallet - it is all on-chain. Each row's `valueNative` is in ITS coin's quote asset (`quoteAsset`; null = native): convert each row before summing a portfolio. |
getWalletPnl getWalletPnl(wallet: string): Promise<WalletPnlView> | A wallet's realized and unrealized PnL across every coin it has ever traded, held and exited alike. `totalPnlPct` is null when nothing was spent - a zero basis has no percent. Each coin's figures are in ITS quote asset (`quoteAsset`; null = native), so a total across coins converts each row first. |
getWalletTrades getWalletTrades(wallet: string, query?: WalletTradesQuery): Promise<WalletTradesView> | Every trade a wallet has made, newest first. `mint` narrows to one coin; page with the last row's `timeMs` as `before`. |
getWalletTradingStats getWalletTradingStats(wallet: string): Promise<WalletTradingStatsView> | A wallet's lifetime trading aggregates plus the 24h/7d/30d/all windows in one read (a window switch must not cost a round trip). Public by wallet, like the holdings and PnL reads. TWO HONESTY LEVELS in one payload, worth carrying into whatever you render. The per-coin aggregates (counts, volumes, realized PnL, the win rate) fold rows that are never pruned, so they are lifetime-exact. Anything folded from the trade TAPE - fees, average and largest trade, every window - is bounded by the tape's retention, so a heavy wallet's earliest trades on a busy coin may simply be gone. Both cover BONDING-CURVE trading only. |
getWalletPnlCurve getWalletPnlCurve(wallet: string): Promise<WalletPnlCurveView> | A wallet's cumulative realized-PnL curve, ascending and downsampled (the first and last real trades always survive). Its own read because the replay is the expensive one. `complete: false` means retention pruned part of the tape: the difference between the replay and the stored lifetime truth is folded into every point as `baselineRealizedNative`, so the LAST point is always right and the early ones are approximate. Say so rather than drawing an exact-looking early curve. |
getCreatorStats getCreatorStats(wallet: string): Promise<CreatorStatsView> | A wallet's creator-side aggregates: what it launched, how much graduated, fees collected, reach. A wallet that never launched reads back the zeroed shape, not a 404. Deliberately carries no claimable-now figure - that is a point-in-time chain read, and serving it under a cache TTL would show a stale claim amount. |
Launching
| Method | Description |
|---|---|
buildLaunch buildLaunch(request: LaunchBuildRequest): Promise<LaunchBuildResponse> | Build a coin launch - the ONE transaction the platform still builds, because it is the one a client cannot build for itself: the API predicts the coin's CREATE2 address before the transaction exists and writes the registry row keyed on it. The wallet signs AND broadcasts. Report the hash with `confirmLaunch`, then read the receipt from your own RPC. Requires a live session with the target chain's linked wallet, and a tight rate-limit bucket. The request's `imageKey` is a sha256 content-address, NOT a URL - get one from `uploadAndAwaitReady` (or `uploadAsset` plus your own poll). An arbitrary hash is refused with image-not-found. |
confirmLaunch confirmLaunch(mint: string, request: LaunchConfirmRequest): Promise<LaunchRecord> | Record a broadcast launch's transaction hash. It does not itself flip lifecycle state - the API's on-chain verifier owns that. Requires the caller to own the launch. |
editCoinDetails editCoinDetails(mint: string, request: CoinDetailsEditRequest): Promise<CoinDetailsEditResponse> | Replace a coin's description + links (the universal edit pathway). REPLACE semantics: the request is the full editable set, and an omitted or empty field CLEARS that detail. Image, name and ticker are launch-time identity and are not editable. Gated on being the coin's RESOLVED creator - the launch creator unless an accepted creator handoff moved the role - with a 403 whose `error` is the stable identifier `coin creator required` otherwise. The returned record carries the coin's NEW `metadataUri`; the old URI keeps serving the old JSON. |
Watchlist and sentiment
| Method | Description |
|---|---|
getWatchlist getWatchlist(): Promise<WatchlistView> | The caller's watchlist - their starred coins, each joined with enough market context to render a row without a second read, newest star first. Requires a linked wallet (the list belongs to the WALLET, not the session); without one the API answers 403. |
watchCoin watchCoin(mint: string): Promise<WatchlistToggleView> | Star a coin. Idempotent, and returns the coin's fresh PUBLIC watcher count - render that rather than a local increment, since the caller may not even qualify for the count. |
unwatchCoin unwatchCoin(mint: string): Promise<WatchlistToggleView> | Unstar a coin. Idempotent, and works on a coin that has left the registry - otherwise the star would be unremovable. |
setCoinSentiment setCoinSentiment(mint: string, vote: SentimentVote | null): Promise<CoinSentimentView> | Cast, change, or clear the caller's vote (`vote: null` un-votes - re-clicking the face you picked). Returns the fresh view, so the surface renders the SERVER's tallies rather than a local increment. Gated on having BOUGHT the coin: a wallet that has bought less than `minBuyUsd` of it is refused with a 403 whose `error` is the stable identifier `sentiment buy required`. Read `canVote` first and disable the affordance - the view carries both it and the threshold, so the gate can be stated before anything is refused. |
Session and profile
| Method | Description |
|---|---|
walletChallenge walletChallenge(request?: WalletChallengeRequest): Promise<WalletChallenge> | Start linking a wallet to the caller's session: returns the exact single-use, short-lived challenge message the wallet must sign. Requires a live session - the API answers 401 otherwise. |
walletLink walletLink(request: WalletLinkRequest): Promise<WalletLink> | Complete the link with the wallet's address and its EIP-191 `personal_sign` signature over the challenge. |
walletUnlink walletUnlink(request?: WalletUnlinkRequest): Promise<WalletUnlink> | Clear the session's wallet link - the disconnect path. Without it a wallet switch leaves the OLD wallet as the session identity until some lazy re-link fires. |
walletModeration walletModeration(): Promise<WalletModeration> | The caller's own moderation standing, combined across their linked wallets. Check it before offering a trade you build YOURSELF. Building client-side means there is no server build left to refuse a banned wallet outside the world, so this is the check that used to happen implicitly - the chain will happily execute a banned wallet's swap. |
getProfile getProfile(wallet: string): Promise<Profile> | Any wallet's PUBLIC profile - handle and avatar. An unregistered wallet reads back empty, never an error. |
getMyProfile getMyProfile(): Promise<Profile> | The caller's own profile. Requires a live session with a linked wallet; fields are null until set. |
updateProfile updateProfile(request: ProfileUpdateRequest): Promise<Profile> | Update the caller's own profile: set or change the handle, set or clear the avatar. The avatar is an upload content-address from `uploadAndAwaitReady` (null clears it); a still-processing one is a 409 that succeeds on retry, and a video is a 415. A taken handle also rejects with a 409 ApiError. |
checkHandle checkHandle(handle: string): Promise<UsernameAvailability> | Is this handle free? Public and anonymous, safe at typing cadence. ADVISORY ONLY - the save-time unique index is the arbiter, so `updateProfile` can still 409 on a handle this said was available. `reason` says WHY a refused one is refused (invalid / reserved / taken). |
Media uploads
| Method | Description |
|---|---|
uploadAsset uploadAsset(body: AssetBody, contentType: string): Promise<MediaUpload> | Upload media bytes and get back a HANDLE, not a URL. The platform never serves user-supplied bytes: an upload lands private and a worker re-encodes it, so `url` is null at this moment and `status` is what matters. Usually 'pending' - but 'ready' immediately when identical bytes were derived before, since uploads are content-addressed and dedupe. This is the ONLY way to obtain the `imageKey` that `buildLaunch` and the avatar field of `updateProfile` take: those are sha256 content-addresses the API mints in response to an upload, so an arbitrary hash is refused. Session + linked wallet required. Oversized bytes reject as an ordinary ApiError with `status` 413. |
getMedia getMedia(key: string): Promise<MediaUpload> | Derivation status for an `uploadAsset` handle. Poll until `status` leaves 'pending'/'processing'; 'ready' carries the derived `url` (and `posterUrl` for video). |
uploadAndAwaitReady uploadAndAwaitReady(body: AssetBody, contentType: string, options?: AwaitReadyOptions): Promise<MediaUpload> | Upload and wait until the platform has finished deriving, returning a handle that is 'ready' (or 'failed'). Bundled because every consumer of `uploadAsset` needs this loop before it can use the key for anything, and hand-rolling it means re-deriving the poll interval, the timeout, and the fact that 'failed' is terminal. An upload that dedupes to an already-derived asset returns without polling at all. Rejects with an ApiError-free plain Error on timeout; the handle is still valid, so a caller that would rather keep waiting can go back to `getMedia`. |
World reads
| Method | Description |
|---|---|
getWorldProps getWorldProps(): Promise<WorldPropsSnapshot> | Every runtime-placed prop for the deployment's world - what a renderer draws instead of hardcoded scenery. |
getWorldPlayers getWorldPlayers(world?: string): Promise<WorldMapPlayers> | Anonymous player-dot positions for the world map. Server-cached, so seconds-fresh. |
searchWorldPlayers searchWorldPlayers(q: string, world?: string): Promise<WorldPlayerSearch> | Search online players by display-name substring. |
getBazaar getBazaar(): Promise<BazaarSnapshot> | The bazaar stall allocation: every slot with the coin currently placed at it, or vacant. |
getRing getRing(): Promise<RingSnapshot> | The first-ring showcase: every pedestal with the graduated coin currently showcased at it, or reserved-empty. |
getAdBoards getAdBoards(world?: string): Promise<AdBoardsSnapshot> | The world's ad layer: every board plus whatever is showing on each right now. A placement's `endsAtMs` is the render layer's own refresh deadline - a board whose placement lapsed keeps showing until the next read, so poll at least that often on a board that matters. |
getAdPulse getAdPulse(world?: string): Promise<AdVenuePulse> | Venue reach: 24h volume, trades and traders, plus live players and board occupancy. Coarse and server-cached. |
Support
Integration questions, bug reports, package access, and partnership requests go to hello@faze.fun; when referencing Faze data, attribute it to the platform and link back where practical.