Rising Tide Developers
API

Users and Collections

Resolve a user by address, read what they own and earn, manage their links and roles, and curate collections.

Every payout address in the protocol resolves to a user, so an address is the practical lookup key: prefer /api/users/address/{stxAddress} over the numeric id wherever you have a chain address in hand. Resolving many at once, use batch-lookup rather than a loop.

Identity is owned by the profile hub. A client app should render a profile and link out to the hub to edit it, not write to PATCH /api/users/{id}.

Identity

MethodPathAuthPurpose
GET/api/usersapp keyList users.
POST/api/usersapp key + userSign-up and profile upsert. The session token must prove the stxAddress in the body, or it is a 403. An invite code rides in the X-Invite-Code header or the body's inviteCode, and is claimed in the same transaction that creates the account, so an invalid code creates no user. A new user on an app that requires an invite and sends none is a 403 with code INVITE_REQUIRED.
POST/api/users/connectapp key + userSign-in handshake. Links an existing user to the calling app and answers { exists, linked }. It never creates a user: signup is POST /api/users.
POST/api/users/me/storage-walletapp key + userRecord the caller's storage wallet: the Privy embedded EVM wallet the app created in their session. Confirmed against Privy; idempotent; 409 for a bring-your-own-wallet account.
GET/api/users/me/storageapp key + userThe caller's storage posture: wallet, free allowance (bytes and about-N-pages), credits in winc and as pages, whether room can be bought and on what terms, automatic destination, and how many owned editions are saved but not written. Null means the bundler could not be read.
PATCH/api/users/me/storageapp key + userSet saveAsDefault (NONE or ARWEAVE). ARWEAVE needs a storage wallet.
POST/api/users/me/storage/checkoutapp key + userStart a card payment that adds room to the caller's own storage wallet. amount is in the currency's smallest unit and must sit inside the offer the posture carries. 409 when the paid rail is off or the caller has no storage wallet; 503 when the destination is not quoting.
GET/api/users/searchapp keySearch users by name or address.
POST/api/users/batch-lookupapp keyResolve many addresses to users in one call. Use this instead of a loop.
DELETE/api/users/{id}app key + userDelete a user.
GET/api/users/{id}app key + user, entitlementOne user by numeric id, with the contact fields (email, xHandle, Privy ids) that every other user route blanks. Operator read: needs VIEW_ADMIN_PANEL. Apps look a person up by address.
PATCH/api/users/{id}app key + userUpdate a profile. Identity is owned by the profile hub - client apps should link out rather than write here.
GET/api/users/address/{stxAddress}app keyOne user by Stacks address. This is the lookup most apps want.
GET/api/users/address/{stxAddress}/profileapp keyPublic profile readout: name, bio, avatar, links.

What a user owns and earns

MethodPathAuthPurpose
GET/api/users/address/{stxAddress}/instancesapp keyEverything this address owns.
GET/api/users/address/{stxAddress}/revenueapp keyWhat this address has earned, by source.
GET/api/users/{id}/contributionsapp keyEvery contribution row naming this user.
GET/api/users/address/{stxAddress}/collectorsapp keyWho collects this creator.
GET/api/users/address/{stxAddress}/supportingapp keyWho this address collects.
GET/api/users/address/{stxAddress}/arweaveapp keyPermanent-storage records for this address.

Activity and notifications

MethodPathAuthPurpose
GET/api/users/address/{stxAddress}/activityapp keyThis address's activity stream.
GET/api/users/address/{stxAddress}/feedapp keyThe feed shown on a profile.
GET/api/users/address/{stxAddress}/notificationsapp keyIn-app notifications for this address: the last things that involved it and that it did not do itself. appId narrows to one app, limit is 1-100 (default 30) and cursor pages with the nextCursor of the last answer. Answers items, nextCursor, unreadCount, unreadCapped and readAt. Never cached.
POST/api/users/address/{stxAddress}/notifications/readapp key + userMove the read watermark, optionally to { readAt } (ISO timestamp, default now). Only the address's own session may: anyone else is a 403. It only moves forward, and is a separate call from the feed so that fetching never marks anything read.
GET/api/users/address/{stxAddress}/achievementsapp key, user optionalThe shelf: awards earned, plus exactly one next rung (or the graduated state) when the bearer token is the address. A stranger gets the awards and next: null. ?appId= says which app the viewer is standing in.
GET/api/achievements/ladderapp keyThe ladder as a map: every rung in order, what earns it, what it pays, and its precursor - the rung that must be held first (null on the first rung and on the return family). No address and no bearer token - the rungs are the same for everybody. Join it with the shelf on slug to mark where a viewer stands and which rungs are locked.

Web Push

Push delivers the same items as the notification feed above, to a device, while the app is closed. Sending is switched off until the server is given a key: while it is, the key route answers 503 and a browser cannot subscribe without that key, so treat 503 as push not being offered. A browser subscription belongs to one origin, so a device subscribed in two apps holds two subscriptions. Each item is pushed through the app it belongs to, or through the hub when the person has no subscription in that app, and never through both.

MethodPathAuthPurpose
GET/api/push/vapid-public-keyapp keyThe VAPID public key to pass as applicationServerKey. 503 when push is not configured, which means push is not offered.
GET/api/push/subscriptionsapp key + userEvery device the signed-in person receives push on, across all apps. Endpoints are never returned.
POST/api/push/subscriptionsapp key + userSave this device: { appId, endpoint, keys: { p256dh, auth } }. The endpoint must belong to a browser push service (FCM, Mozilla, Apple, WNS). An app-scoped key may only name its own app. A person holds at most ten devices per app: an eleventh is a 409 TOO_MANY_DEVICES.
DELETE/api/push/subscriptionsapp key + userStop pushing to a device: { endpoint } for this one, or { id } from the list. Only the caller's own rows.
POST/api/push/opensapp key + userRecord a tap: { deliveryId } from the payload. Stamps the ledger row once, and only when it is the caller's own; { recorded } either way. RisingTideProviders sends it for you.

The service worker receives a PushPayload: the NotificationItem itself, a more count of items folded into the push, an app-neutral fallback sentence to show for any kind the app does not recognise, a badge count, and a deliveryId. Carry the id on the URL a tap opens, as ?via=push&pd=<deliveryId>, and the app records the tap when it loads.

MethodPathAuthPurpose
GET/api/users/address/{stxAddress}/appsapp keyThe app catalog as this user sees it, each entry OPEN, UNLOCKED or LOCKED. Membership comes from the catalog and the user's grants; activity only orders it, and never confers access. includeHidden=true adds the apps they hid from the rail.
PATCH/api/users/address/{stxAddress}/apps/{appId}app key + userShow or hide an app on the caller's own rail: { displayInRail }. Self only. A gated app the caller holds no grant for cannot be added; hiding is always allowed.
GET/api/users/{id}/appsapp keyApp access and activity, by user id.
GET/api/users/{id}/linksapp keySocial links.
POST/api/users/{id}/linksapp key + userAdd a social link.
DELETE/api/users/{id}/links/{linkId}app key + userRemove a link.
GET/api/users/{id}/links/{linkId}app keyOne link.
PATCH/api/users/{id}/links/{linkId}app key + userUpdate a link.
GET/api/users/{id}/rolesapp keyRoles held.
POST/api/users/{id}/rolesapp key + user, entitlementGrant a role. Needs MANAGE_ROLES.
DELETE/api/users/{id}/roles/{userRoleId}app key + user, entitlementRevoke a role grant. Needs MANAGE_ROLES.
GET/api/users/{id}/roles/{userRoleId}app keyOne role grant.
GET/api/users/{id}/invitesapp keyInvites this user has claimed. bindingValue is always null here, because the route answers an app key and names no person.
GET/api/users/{id}/test-accountsapp keyLinked test accounts.
POST/api/users/{id}/test-accountsapp key + userLink a test account.
DELETE/api/users/{id}/test-accounts/{accountId}app key + userUnlink a test account.
GET/api/users/{id}/test-accounts/{accountId}app keyOne test account.
PATCH/api/users/{id}/test-accounts/{accountId}app key + userUpdate a test account.

Collections

MethodPathAuthPurpose
GET/api/collectionsapp keyList collections.
POST/api/collectionsapp key + user, entitlementCreate a collection. Needs MANAGE_LISTINGS.
DELETE/api/collections/{id}app key + userDelete a collection.
GET/api/collections/{id}app keyOne collection.
PATCH/api/collections/{id}app key + userUpdate a collection.
GET/api/collections/by-slug/{slug}app keyResolve a collection by slug.
GET/api/collections/{id}/itemsapp keyItems in a collection.
POST/api/collections/{id}/itemsapp key + userAdd an item.
DELETE/api/collections/{id}/items/{itemId}app key + userRemove an item.
PATCH/api/collections/{id}/items/{itemId}app key + userUpdate an item.
POST/api/collections/{id}/items/reorderapp key + userReorder items.
GET/api/collections/{id}/analyticsapp keyAggregate counters for a collection.