api reference (for developers): integrating with the postfun protocol
introduction: build on the cultural value layer
the postfun api provides programmatic access to our platform's data and functionality. we've designed it to be restful, robust, and intuitive, allowing developers to extend postfun's capabilities and build innovative tools on top of our cultural value protocol. whether you're creating analytics dashboards, automating trading strategies, or integrating postfun data into other applications, this reference will guide you.
disclaimer
this api reference details the interfaces used by our official clients (website and browser extension). while we encourage community development, please be aware that the api is subject to change. for high-volume use cases or to request direct access to authenticated endpoints (for non-browser environments), please contact our team via discord or partnerships@postfun.xyz to discuss your specific needs.
authentication: nostr-powered session management
postfun uses a hybrid authentication model: nostr for identity, jwt for session.
1. post /auth/login
-
purpose: authenticates a user based on a signed nostr event and issues a json web token (jwt) for subsequent api requests.
-
authentication: none (this is the login endpoint itself).
-
request method:
post -
endpoint:
https://api.postfun.xyz/auth/login -
request body (
application/json): a nostr event object (kind 22242) signed by the user'snsec. thecontentfield must contain achallengestring provided by a preceding request to the backend (not directly exposed here for simplicity, but assumed to be handled by the client'ssigneventflow).{
"id": "e0e2...",
"pubkey": "b47c...",
"created_at": 1678886400,
"kind": 22242,
"tags": [],
"content": "{\\"challenge\\": \\"your_unique_challenge_string\\", \\"purpose\\": \\"postfun login\\"}",
"sig": "f1f2..."
} -
response (200 ok -
application/json):{
"token": "eyjhbgcioijsuzyijiuzi1niisinr5cci6ikpxicj9.eyj1c2vyx2lkijoiytyyyjc5mtitytc0yiotngrilotk0njqtotu2mthhnmy0otqziijwcgv5ijoiyjq3yzu1ndu0zjyymjawm2vlm2rkontjmxrjnhjkywm0nzikmxwcmnvzlmqxndq5otkxztm0mjaifq.signature"
} -
error responses:
400 bad request: invalid event structure, missing fields.401 unauthorized: invalid signature, expired challenge,pubkeymismatch.
subsequent requests: once a jwt is obtained, it must be included in the authorization header for all protected endpoints: authorization: bearer <your_jwt_token>.
4.2. public data endpoints (no authentication required)
these endpoints provide read-only access to public postfun data.
1. get /stats
- purpose: retrieve platform-wide aggregate statistics.
- response (200 ok -
application/json):{
"total_assets_cumulative": 152345,
"new_assets_24h": 345,
"total_liquidity_sats": 123456789000,
"liquidity_24h_sats": 5678901230,
"total_volume_sats": 987654321000,
"volume_24h_sats": 4321098760
}
2. get /tweets
- purpose: retrieve a paginated list of content pools based on various filters.
- query parameters:
by(string, optional): sort order. accepted values:new(default),volume,level,gainers,losers.page(integer, optional): page number for pagination (default: 1).limit(integer, optional): number of results per page (default: 20, max: 100).
- response (200 ok -
application/json):[
{
"id": "a1b2c3d4e5f6g7h8",
"tweet_id": "1678886400000000000",
"tweet_username": "elonmusk",
"tweet_content_snippet": "just bought a new dog. much wow. 🐕",
"minter_npub": "npub1...",
"current_price_sats_per_token": 0.00000125,
"total_volume_sats": 50000000,
"current_liquidity_sats": 8000000,
"current_level": 2,
"created_at": "2023-08-16T10:00:00Z"
},
{
"id": "b2c3d4e5f6g7h8i9",
"tweet_id": "1678886400000000001",
"tweet_username": "balajis",
"tweet_content_snippet": "the network state is emerging...",
"minter_npub": "npub1...",
"current_price_sats_per_token": 0.000005,
"total_volume_sats": 150000000,
"current_liquidity_sats": 15000000,
"current_level": 3,
"created_at": "2023-08-15T18:30:00Z"
}
]
3. get /tweets/{tweetId}
- purpose: retrieve detailed information for a specific content pool.
- path parameters:
tweetId(string, required): the original x.com tweet id.
- response (200 ok -
application/json):{
"id": "a1b2c3d4e5f6g7h8",
"tweet_id": "1678886400000000000",
"tweet_username": "elonmusk",
"tweet_content_full": "just bought a new dog. much wow. to the moon and beyond with doge!",
"minter_npub": "npub1l4t...",
"creator_npub": "npub1n0x...",
"current_price_sats_per_token": 0.00000125,
"virtual_sats_reserve": 10500000.0,
"token_reserve": 800000000.0,
"bitcoin_reserve": 1500000,
"total_volume_sats": 50000000,
"current_level": 2,
"next_level_target_sats": 10000000,
"graduation_target_sats": 100000000,
"status": "ACTIVE",
"created_at": "2023-08-16T10:00:00Z",
"holders_count": 125,
"swaps_count": 560,
"recent_swaps": [
{
"swap_id": "s_xyz789",
"user_npub": "npub1a2b...",
"direction": "BUY",
"amount_in_sats": 100000,
"amount_out_tokens": 8000000,
"fee_sats": 10000,
"timestamp": "2023-08-16T14:35:00Z"
}
],
"top_holders": [
{"npub": "npub1c3d...", "amount_tokens": 500000000},
{"npub": "npub1e4f...", "amount_tokens": 100000000}
]
}
4. get /users/{twitterUsername}
- purpose: retrieve public-facing information about a linked x.com user.
- path parameters:
twitterUsername(string, required): the x.com username (e.g.,elonmusk).
- response (200 ok -
application/json):{
"twitter_username": "elonmusk",
"is_linked_to_postfun": true,
"minted_posts_count": 5,
"total_earned_sats": 12345000
}
4.3. authenticated endpoints (jwt required)
these endpoints require an authorization: bearer <jwt> header in the request.
1. get /me
- purpose: retrieve the currently authenticated user's detailed private information.
- response (200 ok -
application/json):{
"id": "a62b7912-a74b-4db6-9464-95618a6f4943",
"npub": "npub1l4tm00000000000000000000000000000000000000000000000000000000",
"balance_sats": 500000,
"linked_twitter_username": "your_twitter_handle",
"available_claim_sats": 15000,
"holdings": [
{"asset_id": "a1b2c3d4e5f6g7h8", "amount_tokens": 10000000, "current_value_sats": 12500},
{"asset_id": "b2c3d4e5f6g7h8i9", "amount_tokens": 500000, "current_value_sats": 2500}
],
"recent_deposits": [
{"id": "d_123", "amount_sats": 100000, "status": "COMPLETED", "timestamp": "2023-08-15T12:00:00Z"}
],
"recent_withdrawals": [
{"id": "w_456", "amount_sats": 50000, "status": "COMPLETED", "timestamp": "2023-08-14T18:00:00Z"}
],
"recent_swaps": [
{"id": "s_789", "asset_id": "a1b2c3d4e5f6g7h8", "direction": "BUY", "amount_sats": 10000, "timestamp": "2023-08-16T14:35:00Z"}
]
}
2. post /mints
- purpose: create a new content pool for a specific tweet.
- request body (
application/json):{
"tweet_id": "1678886400000000000"
} - logic:
- authenticated user must have at least 1,000 sats in their balance.
- tweet must not have an existing
postfunpool. - a
mintjob is queued for asynchronous processing. the 1,000 sats fee is immediately deducted from the user's balance.
- response (202 accepted):
{ "message": "mint job queued successfully. please check your dashboard for status." }
3. post /swaps
- purpose: execute a buy or sell transaction for a content pool token.
- request body (
application/json):{
"tweet_id": "1678886400000000000",
"direction": "BUY",
"amount_in_sats": 10000,
"min_amount_out": 5000000
} - logic:
- validate user's balance for
amount_in_sats(for buy) oramount_in_tokens(for sell). - ensure
amount_in_satsis at least 1 sat (minimum input). - a
swapjob is queued for asynchronous processing.
- validate user's balance for
- response (202 accepted):
{ "message": "swap job queued successfully. transaction pending." }
4. post /deposits
- purpose: request a lightning network invoice to deposit sats into the user's custodial wallet.
- request body (
application/json):{
"amount_sats": 50000,
"memo": "deposit to postfun account"
} - logic:
- checks if the user has too many pending deposit invoices. (limits concurrency for security/operational efficiency).
- requests a bolt11 invoice from the integrated lightning service.
- stores the invoice details (payment hash, expiry) in the
depositstable withstatus='PENDING'.
- response (200 ok):
{ "payment_request": "lnbc500n1p..." }
5. post /withdrawals/initiate
- purpose: initiate a lightning network withdrawal by providing an invoice. returns fee information.
- request body (
application/json):{
"invoice": "lnbc100u1p..."
} - logic:
- decodes the provided bolt11 invoice.
- calculates the withdrawal fee: 0.5% of amount or 10 sats, whichever is higher.
- checks if the user's current
balance_satsis sufficient to cover the withdrawal amount + fee.
- response (200 ok):
{
"decoded_amount_sats": 10000,
"calculated_fee_sats": 50,
"total_sats_debited": 10050,
"memo": "withdrawal from postfun"
}
6. post /withdrawals/confirm
- purpose: confirm and queue a lightning network withdrawal after user reviews fees.
- request body (
application/json):{
"invoice": "lnbc100u1p..."
} - logic:
- re-validates the invoice and user's balance.
- queues a
withdrawaljob for asynchronous processing.
- response (202 accepted):
{ "message": "withdrawal job queued successfully. payment will be processed shortly." }
7. post /users/link-twitter
- purpose: securely link an x.com account to the authenticated
postfunuser'snpub. - request body (
application/json):{
"tls_notary_proof": { /* ... raw tls notary proof object ... */ }
} - logic:
- receives the tls notary proof.
- uses an internal verifier to validate the proof (e.g., checks against x.com's certificate, proves user's session).
- if valid, extracts the x.com username/id from the proof.
- links the authenticated
user_idto thetwitter_usersrecord, marking it asverified.
- response (200 ok):
{ "message": "twitter account successfully linked.", "linked_username": "elonmusk" }
8. post /claims
- purpose: for a content creator to claim their accumulated
earned_sats(fees and bonuses) into their mainbalance_sats. - request body (
application_json):{}(no specific body, as user is identified by jwt). - logic:
- verifies the authenticated user has a linked and verified x.com account with a non-zero
earned_satsbalance. - queues a
claimjob. the worker will atomically transfer theearned_satstobalance_satsand resetearned_satsto zero.
- verifies the authenticated user has a linked and verified x.com account with a non-zero
- response (202 accepted):
{ "message": "claim job queued successfully. funds will appear shortly." }