# DeSo Vision

Decentralized Social is empowering an internet that’s creator-led, user owned, and open to millions of developers around the world to build off one another.

{% embed url="<https://www.youtube.com/watch?v=kPPb_S5Ry5E>" %}
Learn about DeSo in 90-seconds — <https://deso.com>
{% endembed %}

## Scaling From DeFi to DeSo <a href="#moving-from-defi-to-deso" id="moving-from-defi-to-deso"></a>

The DeSo blockchain is a layer-1 blockchain built from the ground up to power storage-heavy applications like social media use-cases and advanced trading applications. It costs over $100 to make a 200-character "Tweet" on Ethereum, and over $2 on Solana, yet only 1/10,000th of a cent on DeSo. The same goes for storing any content, including financial content like a resting limit order on an order-book exchange. This content storage advantage gives the DeSo Blockchain the unique ability to not only marry social content with crypto for the first time (see [Focus](https://focus.xyz), [docs](https://docs.google.com/document/d/14Um8ErmoE8IhgZrACSI2FeTo2yji2Q1Hxvw7KNoozM8/edit?tab=t.0)), but also to improve on core DeFi primitives like order-book exchanges and perpetuals exchanges (see [Openfund](https://openfund.com), [docs](/openfund/what-is-openfund)).

## Centralization of Social Media

Today, social media is even more centralized than the financial industry was, prior to the creation of Bitcoin. A handful of private companies effectively control public discourse and earn monopoly profits off of content that they don't even create.

Meanwhile, the creators who actually produce this content are underpaid, under-engaged, and under-monetized thanks to an outdated ads-driven business model.

In addition to all of this, the ads-driven business model also forces social media companies to keep a walled garden around content created on their platforms, preventing external developers from innovating or building apps on top of it and giving users and creators no choice but to continue using apps that solely they control.

These problems stem from the fact that the data and content created by users today are privately owned by a handful of companies, rather than publicly accessible as an open utility.

Because only a handful of companies have access to the content, only these companies can curate competitive feeds, only these companies can build competitive new features and apps, and only these companies can monetize this content — content that isn't even created by these companies in the first place.

We're stuck in a loop:

1. Users have to use these companies' apps because they have a monopoly on the content.
2. This forces creators into continuing to give their content up to them in order to get reach.

This results in a vicious cycle that continues to empower these companies at the expense of creators and society as a whole.

These companies have managed to create a global network effect around a private pool of content that they solely monopolize.

Moreover, this centralization of content seems unavoidable: There's value in combining all of the content into a single pool, since it allows for curation at a global scale, but whoever we put in charge of maintaining the pool is ultimately going to become a centralized gatekeeper like what we have today.

A solution would arise if we had a way to shift the network effect to a public pool of content that no individual entity controls — *but can it be done?*

We believe all of these problems can be solved by decentralizing social media in the same way Bitcoin and Ethereum are decentralizing the financial system.

In particular, Bitcoin created a way to store transactions on a public ledger that no individual entity can monopolize, which has led to the disruption of the financial industry, and we believe this technology can now be extended, for the first time, to run a social network without needing to rely on a centralized gatekeeper.

Bitcoin and Ethereum have shown that dominant platforms can be built around open code and open data, rather than around private companies that monopolize their data and benefit shareholders at the expense of everyone else.

This open model for software is already disrupting financial institutions all over the world, from banks to exchanges, and we think, for the first time, this model can be extended to disrupt the social media giants and their outdated ads-driven business models.

If we can start putting social media content into a public blockchain, rather than giving it to a handful of private companies to monopolize, we believe we can create an economy of scale around that blockchain that is powerful enough to rival, and ultimately surpass, what the traditional social media giants have created.

In some sense, we can solve a collective action problem among independent publishers by making it individually rational for them to contribute their content to a new globally-shared pool that they can never be di-intermediated from and that, for the first time, isn't controlled by a single company.

## The Ultimate Vision

Today, a post submitted to Instagram, TikTok, or Twitter belongs to these corporations, rather than the creator who posted it. And the monetization goes predominantly to these corporations as a result.

In contrast, DeSo stores all of its data on a public blockchain, which means that anyone in the world can run a node that exposes their own curated feed.

### The Future "Curator" Economy

Moreover, there is no reason why other "verticalized" players can't enter the market to create feeds that they're uniquely suited for curating.

For example, imagine if ESPN ran a node that curated a feed of the best sports content. Or if Politico ran a node that curated a feed of the best political content.

Additionally, since DeSo is fully open-source, these players could even customize their UI and build custom algorithms to rank the influencers and posts in a way that serves their specific target customers.

We think this will quickly move us from a world in which a handful of juggernauts control the dominant feeds to one in which consumers will have thousands of feeds to choose from, each with its own specific focus.

On top of that, storing all of the data on a public blockchain makes it so that, with one engineer, anyone can build a social media experience that's competitive with the existing incumbents. It cannot be overstated the extent to which this lowers the barrier to entry for creating new social media products.

It becomes possible for existing publishers to trivially spin up social apps and experiences as direct adjacencies to their core business, and allows upstarts to innovate on a relatively even footing with megacorps for the first time.\
\
Compare this to today where building a competitive social app generally requires building a billion-user data moat first.

The best part is that anyone who runs a node to curate their own feed also contributes data back to the public pool of profiles, posts, follows, etc... that's stored on the public blockchain.

A post or a like on ESPN's node can be surfaced on Politico's feed. A post made in China can be surfaced on a feed running on a node in America and vice versa.

And with every node that runs, more content gets contributed back to the global data pool stored on the blockchain, making every other node on the network more powerful and more engaging to users.

In some sense, DeSo can solve a collective action problem among independent publishers: Instead of being forced to contribute to a privately-owned data pool controlled by a megacorp who's not aligned with them, publishers can now contribute to a public data pool that nobody controls and that they'll never be dis-intermediated from.

Thus we can move from a world in which data is a heavily guarded, privately-owned resource to one in which it is more like a globally accessible utility that anyone can build on.

Importantly, there is a strong incentive for publishers to contribute data back to the blockchain because not doing so would deter the top creators from wanting to publish on them.

After all, why would you publish solely on a closed platform that exclusively owns your data when you could additionally publish to the blockchain and have your post instantly available to every node/feed that's running on the internet?

We think all of the above can give the creators unprecedented reach, and a more direct relationship with their followers than has been afforded to them with existing platforms. But reach is only one side of the coin — the other side is monetization.

### The Future "Creator" Economy

Social tokens, social NFTs, and social tipping, three categories of products pioneered by DeSo, are already changing the game in terms of how creators monetize on the internet, but they're only the beginning.

Because DeSo is money-native and open-source, anyone in the world can start to experiment with new ways for creators to monetize by building an app on top of DeSo.

For example, imagine a major creator who wants to start offering premium content in exchange for a monthly subscription.

All it takes is for one person on the internet to build this feature, and the entire ecosystem of DeSo applications gets access to it instantly.

The same goes for other features like an inbox where creators can be paid to repost content, or paid to answer messages from their followers.

And this goes for other things like detecting harmful content or weeding out spam, where the best machine learning researchers in the world can build solutions, with access to the full firehose of data, without asking for permission, no matter where they are.

### The Future of Open Standards

The DeSo blockchain is fundamentally an open protocol that the entire world can build on collaboratively, which we believe will ultimately create even more ways to unlock creators' true potential, and which will bring competition and innovation back to social media.

Moreover, because DeSo is money-native, new signals emerge that can be used to rank content more effectively. For example, the first experiment that was launched by the bitclout.com app was ranking comments by the social token price of the commenter.

Amazingly, this extremely simple ranking mechanism has already produced results that are competitive with centralized platforms. Ranking messages by coin price has also significantly reduced spam for influencers in a way that's truly unique to DeSo apps, and this is still just the beginning.

Imagine what else will be built off of the "$DESO Signal" once the entire world starts building on and contributing to DeSo.

Finally, it's important to mention that we designed DeSo from the ground up so that the incentives of the system keep it decentralized, even in the long run. Creators have a strong incentive to post directly to the blockchain, rather than to a centralized app that withholds their content from the blockchain.

And there's virtually no possibility for developers to lose access to data or APIs because all the data is publicly available on the blockchain, and they already have all the data when they run a node.

Compare this to traditional social media companies, which start open to build a network effect and then shut off access after they've built a winning data moat.

With your help, we hope to build the DeSo blockchain into an enduring positive force for humanity that can bring competition and innovation back to the internet. The internet started as a fundamentally decentralized ecosystem, but we’re at a point in history where things have concentrated and where innovating is harder than it used to be.

After much thought over the past several years, we are convinced that the pendulum will swing back toward decentralization, perhaps permanently, and we all have an opportunity to be a part of that.

A new generation of applications that the entire world can build collaboratively, unlocking the full potential of human ingenuity.


# DeSo Tokenomics

DESO is the native token of the DeSo Blockchain. It is burned as a fee on every single transaction that is processed by the network, making it inherently scarce over time. It is also used to stake to nodes to secure the network as part of [DeSo's Revolution Proof of Stake Consensus](https://revolution.deso.com). The staking APY is subject to change, update-able by PoS hard fork (see [DeSo Governance](/deso-governance)), and [is always listed on the block explorer's validator page](https://explorer.deso.com/validators).

Simply put, the more transactions that run through the DeSo network, the more fees are burned, and the more scarce the currency. In the short-term, the APY paid to support staking is inflationary, but staking rewards will be lowered over time, and in the short-term they encourage users to stake their DESO, which also has a deflationary effect.

In addition, apps launched by the Core Team, such as [Focus](https://focus.xyz) ([docs](https://docs.google.com/document/u/1/d/14Um8ErmoE8IhgZrACSI2FeTo2yji2Q1Hxvw7KNoozM8/edit)) and [Openfund](https://openfund.com) ([docs](/openfund/what-is-openfund)) serve as [DESO Sinks](/deso-tokenomics/deso-sinks).

**Read the next section to learn about DeSo's founding story, initial supply distribution, and more.**


# No Equity, Just Coins and Code

The DeSo Blockchain was bootstrapped and self-funded by [Nader Al-Naji](https://www.linkedin.com/in/nader-al-naji-86b14a3a/). In 2019, Nader recognized that special-purpose blockchains could vastly out-perform existing approaches on storage-heavy applications like social use-cases and advanced trading applications. And so he set about building DeSo to address what he felt were the largest opportunities in crypto.

Nader and his team, which we often refer to as the DeSo Core Team, worked on developing the blockchain from 2019 until late 2020 when they officially launched the network, and third-party nodes started running. In addition to developing the DeSo Blockchain, the team also developed the first application, called [BitClout](https://docs.bitclout.com/), which went viral and pioneered a concept now known as "Social Tokens." In early 2021, the DeSo Blockchain code was made [100% open-source](http://github.com/deso-protocol/core), solidifying DeSo as a truly decentralized layer-1 platform.

When they launched the network, the Core Team embedded a bonding curve mechanic that would mint DESO for Bitcoin in a fully-decentralized way. The idea was that users could sacrifice Bitcoin to get DESO in much the same way early Bitcoin users sacrificed CPU power to get Bitcoin. Thus the distribution mechanic could distribute DESO tokens in a fully-decentralized way to anyone, without geographic restrictions (much like Bitcoin mining). The details on the economics of this distribution are described in the [Initial Distribution](/deso-tokenomics/initial-deso-distribution) section.

Importantly, although DESO could be purchased through this bonding curve mechanism, no equity has ever been issued or sold to finance the DeSo Blockchain's development. There is no "shareholder class" to create a conflict of interest with the token, DeSo is truly just "coins and code." It was Nader's explicit intent to avoid creating a conflict of interest between equity and tokens, as he saw the negative effects it could have, and this is why he self-funded its development for nearly two years and only issued tokens through a decentralized mechanism that was fully open to the public. This means in practice that, if you own DESO, then you own the exact same asset that everyone else owns, from top-tier VCs to ordinary people.

This lies in stark contrast with other major blockchains, such as Solana, which have a for-profit VC-controlled entity behind them that is wholly separate from the token. We've seen with projects like Uniswap and Brave how this can lead to conflicts of interest, where value accrues to equity-holders who are owed a "fiduciary duty," rather than to token-holders, who don't have the same rights. Indeed, any token backed by a for-profit company like Uniswap or Solana could even be sued by equity-holders for distributing too much value to token-holders, rather than maximally milking the network value for equity-holders. These issues tend to be less important in the early days, but play a key role as networks mature and become structurally important. There does not exist, nor will there ever exist, such a problem with DESO.


# Current DESO Supply

The current supply of DESO is best viewed on the reference DeSo node [here](https://node.deso.org/supply-stats). There are other sources, but this endpoint hits a fully-synced DeSo node, which runs through all of the actual token balances on-chain to compute a value that is up-to-date down to the second.

Due to burn from transactions and APY paid to staking, the value changes over time, and Coinmarketcap and Coingecko are not dynamically-updated at the time of this writing, so it's best to check the nodes themselves as the source of truth.


# Initial DESO Distribution

The DESO supply was initially \~10.8M (prior to any staking rewards being paid out). This DESO was initially distributed by three mechanisms (initially described in detail in [this](https://drive.google.com/file/d/1YYNSURLiDhZSw3quYtrO5OtGqxSN-NdJ/view?usp=sharing) extremely old document, noting that DESO was initially called CLOUT). Notably, no DESO was ever locked, and there is nobody waiting for liquidity so they can dump their coins.

We describe the initial distribution of DESO below in simple terms:

* Bonding Curve Allocation (\~77%). In \~2021, approximately 77% of the initial DESO was sold through an innovative bonding curve mechanism that was fully open to the public. This mechanism was relatively simple: The price started at $0.50 per DESO (priced in Bitcoin), and doubled for every million DESO sold. The price ultimately reached approximately $180, raising \~5k BTC before the bonding curve was disabled by a hard-fork (shortly before DESO's first CEX listing).
  * Every purchase made against the bonding curve has been aggregated and listed in [this sheet](https://docs.google.com/spreadsheets/d/1D-p6AuwWkQGywfnyXmqirPCfQGZNLn70WHARiZam9_s/edit?gid=0#gid=0), with full pricing information for full transparency.
  * Notably, major well-known investors participated in this Bonding Curve period and continue to support the blockchain today, including [Sequoia](https://www.sequoiacap.com/article/diamondhands-spotlight/), [Andreessen Horowitz](https://a16zcrypto.com/portfolio/), [Distributed Global](https://www.distributedglobal.com/), [Hack VC](https://www.hack.vc/team), [TQ Ventures](https://www.tqventures.com/), [North Island Ventures](https://northisland.ventures/), [Blockchange](https://blockchange.vc/), and many others.
* Team Allocation (\~20%). \~20% of the initial supply was allocated to the team that developed the DeSo Blockchain. This is listed in [the sheet](https://docs.google.com/spreadsheets/u/0/?q=deso%20bonding%20curve) along with the bonding curve purchases.
* Proof of Work Mining (\~3%). The DeSo Blockchain was initially secured by Proof of Work mining for maximum decentralization. Once the distribution of tokens evolved to be sufficiently-decentralized, the network transitioned over to [Revolution Proof of Stake](https://revolution.deso.com) in 2024, which no longer distributes tokens to Proof of Work miners.

The above is an exhaustive list of how the initial \~10.8M DESO were allocated.

Later on, in 2024, in order to promote the adoption of staking to secure the network with the launch of [Revolution Proof of Stake](https://revolution.deso.com), a \~20% APY was offered for staking one's DESO to a validator. At the time of this writing, the APY is still 20%, but please check [the block explorer validator page](https://explorer.deso.com/validators) for the most up-to-date value. Although high, the staking APY does not result in the dilution of one's DESO holdings, so long as one stakes their DESO (and indeed one's ownership percentage actually increases when they stake because not all DESO is staked and earning rewards).

**The above list is exhaustive: There are no DESO sources other than what is listed above, and DESO would be fixed-supply if not for staking APY.**

Over time, as transaction volume increases on the network, and as the APY decreases as more validators emerge, we should expect DESO to become deflationary, and possibly hyper-deflationary.


# DESO Sinks

In addition to the natural burn from transactions, the Core Team continues to develop key applications on the DeSo Blockchain that are gaining traction, and that serve as "DESO Sinks." We refer to these projects as such because they each have their own toke that can only be purchased with DESO. The end result is that the success of these projects could result in vast amounts of DESO being purchased in order to gain exposure to them, independent of DESO's fee-burning potential. The largest apps that act as DESO Sinks today are [Openfund](https://openfund.com) ([docs](/openfund/what-is-openfund)) and [Focus](https://focus.xyz) ([docs](https://docs.google.com/document/d/14Um8ErmoE8IhgZrACSI2FeTo2yji2Q1Hxvw7KNoozM8/edit?tab=t.0)). You can see their markets on the DeSo DEX via Openfund [here](https://openfund.com/trade/openfund) and [here](https://openfund.com/trade/focus).

In addition to Openfund and Focus requiring DESO in order to purchase their tokens, it is worth mentioning that Focus in particular pioneers a new kind of token launchpad with a sophisticated "Automated Market-Maker" concept to power it, now years in the making. This is significant because the tokens launched on Focus require FOCUS tokens to be used and locked up in order to purchase them by default, and FOCUS can only be acquired for DESO.


# The BMF: Burn-Maximizing Fee Mechanism

Unlike virtually all other blockchains in existence, the DeSo Blockchain's fees are maximally burned in order to maximize the network value that accrues to the DESO token, without compromising the transaction ordering properties of blockchain fees and without compromising validators' incentives to run nodes.

Although more sophisticated in practice, at a high level the BMF amounts to only paying the log of the fees to validators, while burning the rest. This means that if a fee is \~2x higher, it will only result in a linear increase in validator rewards. This results in higher fees still earning better placement in blocks, but without validators capturing the lion's share of the fees paid for block space priority. Thus a validator can expect to earn very little through transaction fees, as they should, with their operating model relying solely on a commission on delegated stake. Decoupling the fee revenue from validators' operating incentives in this way allows the network to pay validators the minimum required to operate the network while burning as close to 100% of the network revenue as possible. The full system is described in DeSo's open-source code [here](https://github.com/deso-protocol/core/blob/12fb9c8a3301469f1498e41b656fff624e32d083/lib/block_view.go#L4285), and in [the Revolution Proof of Stake Docs](https://revolution.deso.com).

It is important to note, and perhaps surprising, that other blockchains do not optimize validator rewards and fee-burning in this way, even though fee-burning is the ultimate source of scarcity for blockchain networks in the long-term. For example, Ethereum's mechanism is highly-unoptimized, resulting in most of the fees going to "Miner-Extracted Value" or MEV, especially during times of high congestion (which is when most fees are earned). And Solana's mechanic is even less optimized, blindly burning 50% of fees without any serious attempt at optimization whatsoever.

In contrast, DeSo's fee-burning mechanism was designed in direct conjunction with its validator reward mechanics, from the ground up, in order to ensure that both the cost of operating the network in the long-term is minimized and that maximum fees are burned. Failure to think critically about both of these problems together could result in either validators being paid too little to operate nodes or insufficient fees being burned in the long-term. And changing it after-the-fact becomes very difficult due to validators pushing back on economic adjustments that impact them.


# Designed for the End-Game

When the DeSo Blockchain was first being built, it was designed from the ground up for what the team refers to as "the end-game." Every incentive has been intensely scrutinized, and designed to be robust under a state in which the blockchain has become mature, dominant, and structurally important. It is difficult to see the impacts of these design decisions now because we are in the early days of crypto, but we believe that the difference between strong tokenomic incentives and weak ones will have major impacts on society depending on which blockchain ends up winning, and we have taken this extremely seriously from the very beginning.


# DeSo Governance

Changes to the DeSo blockchain happen according to upgrades to its Revolution PoS consensus mechanism, which is described in detail [here](https://revolution.deso.com/) and [here](https://docs.deso.org/deso-validators/run-a-validator), with all current validators and their staking percentages listed on [the DeSo block explorer here](https://explorer.deso.com/validators).

In simple terms, anyone can submit an upgrade to [DeSo’s fully open-source code](http://github.com/deso-protocol/core), but an upgrade to the DeSo blockchain goes through only if 2/3rds of the validators (weighted by stake) upgrade their software before a particular block height. This is similar to how other Proof of Stake blockchains work, such as Ethereum, and it ensures that changes to the blockchain get heavy oversight and buy-in from the major economic players in the ecosystem before they go through.

For the avoidance of doubt, it is impossible to upgrade the DeSo blockchain without a 2/3rds stake-weighted majority accepting the changes, noting that the DeSo blockchain is [fully 100% open-source](https://github.com/deso-protocol/core), and that no individual owns more than 20% of the DESO in existence. Learn about the key repos and how the code works [here](https://docs.deso.org/~/changes/fDLjGJdJathPNuf23Eol/deso-repos/architecture-overview) (outdated but good) and [here](https://docs.deso.org/~/changes/fDLjGJdJathPNuf23Eol/openfund/algorithmic-trading/debugging-tips-and-code-walkthrough).


# DeSo Tutorial (Build Apps)

Everything you need to know to build and deploy your first DeSo app.

### Getting Help

Up-front, if you ever run into trouble and want to talk to someone, the [DeSo PoS Discussion Telegram Channel](https://t.me/deso_pos_discussion) is a great resource. Everyone who runs a node is in there, as well as members of the DeSo core team. Many there are generally very knowledgeable on the ins and outs of the DeSo blockchain, and super helpful to new users trying to understand what’s going on. We used to run a Discord, but we’ve found a simple dev-focused Telegram channel works better.

If you ever run into issues while doing a swap, the [HeroSwap Support](https://t.me/heroswap) channel can help you. This shouldn’t be needed but we include it here for completeness.

And if all else fails, you can always get our attention by @-mentioning @nader, @lazynina, @stas\_kh, or @deso on any DeSo app, such as [Openfund](https://openfund.com), [Focus](https://focus.xyz), and [Diamond](https://diamondapp.com).

### The DeSo Python SDK

Interested in using Python to construct, sign, and submit DeSo Transactions? Check out [the DeSo Python SDK](#the-deso-python-sdk) to get started.

The tutorial that follows is concerned with setting up your dev environment for browsing the main repos, as well as for frontend development using [the DeSo Javascript sdk](https://www.npmjs.com/package/des-protocol). It's a good primer but not required if you just want to build a [Python Market-Making Bot](/openfund/the-deso-python-sdk/market-making-bots) or a [Social AI Agent](/openfund/the-deso-python-sdk/social-ai-agents), for example.

### Dev Setup

We recommend using a JetBrains IDE like [GoLand](https://www.jetbrains.com/go/) to get started. Even if you’re more familiar with tools like Emacs or Vim, using GoLand will make it a lot easier for us to help you debug what’s going on, and to use valuable plugins like GitHub Copilot for AI code suggestions.

Once you’ve set up GoLand, the next step is to import all the DeSo-related projects so that you can hop around the code effectively. You do this simply by executing the following steps:

* `git clone {repo}`
* Open up GoLand
* File > Open > `{project directory}`
* At this point, you will have the option of opening the directory in a new window or ***attaching*** it to your existing project.
  * We recommend simply attaching all projects to a single window so that you can easily search through all of them using `CTRL+SHIFT+F`

We recommend loading up the following projects, for basic app development:

* [deso-examples-react](https://github.com/deso-protocol/deso-examples-react)
  * This is the main repo we’ll be playing with in this guide. Follow the instructions on the README page to set it up. Then import it into your IDE by following the previous steps.<br>
* [deso-workspace](https://github.com/deso-protocol/deso-workspace) (reference only)
  * This repo is intended only as a reference, and it is useful mainly because of the deso-protocol SDK that the example app uses ([README for that is here](https://github.com/deso-protocol/deso-workspace/tree/master/libs/identity)). Attaching this repo to your IDE will allow you to **jump to definitions** by using `CTRL+B`.<br>
* [identity](https://github.com/deso-protocol/identity) (reference only)
  * It’s a bit confusing, but this repo is actually the one that holds the users’ ***owner*** keys, which we’ll talk about later, and it’s also the repo that does all of the signing.<br>
  * Put simply, the deso-workspace identity library, mentioned above, is a ***wrapper*** around this repo, which does all of the **real** heavy lifting.<br>
  * As you will learn later, this repo holds the owner keys, while deso-workspace holds the ***derived*** keys, which are used by each app to sign a limited set of transactions.<br>
* In addition, we recommend adding the other DeSo repos for reference purposes:<br>
  * [core](https://github.com/deso-protocol/core) (reference only)
    * This is DeSo’s layer-1 blockchain code that is run by all nodes on the network, including Coinbase, GateIO, and many others. It is the beating heart of DeSo’s infrastructure.<br>
    * Probably the most useful later on will be the list of all supported transaction types, which you can find [here](https://github.com/deso-protocol/core/blob/df1f4bb941d158675b48419d92ee24111dece621/lib/network.go#L205), with full documentation [here](https://docs.deso.org/deso-backend/construct-transactions). All the functionality the DeSo blockchain supports is encapsulated in this handful of transactions.<br>
    * The transactions included cover:
      * Sending/receiving DESO and other tokens<br>
      * Every NFT operation you can think of, including a fully on-chain marketplace, which no other chain is capable of powering.
        * You can see this functionality on [Diamond](https://diamondapp.com).<br>
      * Every token operation you can think of, including minting/burning, and a fully on-chain order-book exchange that can power 40,000+ matches per second, which no other chain is capable of. We call this the *DeSo DEX*.
        * The DeSo DEX is actually what powers the Openfund trade page [here](https://openfund.com/trade/Openfund). Everything is actually fully on-chain, so you can build your own fully-functional exchange off of it if you wanted to.<br>
      * On-chain end-to-end encrypted direct messages ***and*** group chats, which no other chain supports.
        * You can see this functionality on [Diamond](https://diamondapp.com), and in our chat prototype [here](https://chat.deso.com).<br>
      * The full “Twitter” feature set, including the ability to create a profile with an on-chain profile picture, the ability to submit posts/comments, the ability to follow other users, interact, etc… all fully on-chain.\
        \
        No other chain is capable of powering an on-chain social graph like this.
        * You can see this functionality on [Diamond](https://diamondapp.com) and on [Desofy](https://desofy.app).<br>
  * [backend](https://github.com/deso-protocol/backend) (reference only)
    * The backend repo is a wrapper around the core repo that allows for querying and transaction construction, and it is what powers [node.deso.org](https://node.deso.org).\
      \
      It’s useful to have this repo attached to your project because all of the endpoints for **transaction construction** that you’ll be using live here.<br>
    * Probably the most useful later on will be the list of all the supported backend routes, which you can find [here](https://github.com/deso-protocol/backend/blob/eb04b7c298aeecd0c02aad2c9ea1422887060a6a/routes/server.go). All of these routes can be used to construct transactions, and interact directly with the chain.\
      \
      You can also see all the documentation for the backend routes [here](https://docs.deso.org/for-developers/backend/introduction).<br>
  * [frontend](https://github.com/deso-protocol/frontend) (reference only)
    * This is the frontend code that powers [node.deso.org](https://node.deso.org), and you can see examples for constructing all the relevant transactions we’ll be using in this repo.
    * Probably the most useful later on will be [backend-api-service.ts](https://github.com/deso-protocol/frontend/blob/main/src/app/backend-api.service.ts), which shows how to call all of the backend endpoints from a real-world frontend (though it doesn’t use the deso-workspace/identity library yet unfortunately, it does it through the raw identity library instead).<br>

Once you’ve loaded up all the repos, your GoLand “Project” panel should look something like this.

Simple:

<div><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1576055b-25f0-47e0-bde6-cc939c4ecd4b/Untitled.png" alt=""> <figure><img src="/files/yq72GIoz0CN1IaZZpRLm" alt=""><figcaption></figcaption></figure></div>

Advanced:

<div><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/839539f5-01c3-4a68-89fb-46e89aa8d919/Untitled.png" alt=""> <figure><img src="/files/BbOY9kM4UdV10A67y9ea" alt=""><figcaption></figcaption></figure></div>

If you chose to clone and attach all of the suggested repos (besides MegaSwap), **you actually have 100% of the code powering the DeSo blockchain sitting on your computer right now.**

Kinda cool, right? \
\
Such is the power of 100% open-source development.

### Going Deep (Optional)

For everyone who just wants to **use** the DeSo blockchain, there is no need to run a DeSo node, no need to dive into the core repo, or even to understand how all the repos fit together. **So if you just want to build an app, skip this section!**

The above being said, we know some people will want to understand how everything fits together.&#x20;

For this, there are a couple of other tutorials that you may find interesting:

* [Running a node](https://docs.deso.org/about-deso-chain/readme#running-a-node) (quickstart guide [here](https://docs.deso.org/about-deso-chain/readme#how-to-run-a-node))

  * You already have all of the DeSo **code** on your local machine— but what if you could download the entire **social graph** onto your local machine as well?<br>
  * For most people, it is sufficient to simply use another node such as [node.deso.org](http://node.deso.org) to construct transactions and query.\
    \
    ***BUT*** if you’d like to run your own node, and download all of DeSo’s user data, including all profiles, posts, and follows from the beginning of time, then the above guide will show you how.<br>
  * It will also show you how to build and curate your own feed, if you want.

* [Full code walkthrough](https://docs.deso.org/for-developers/walkthrough) (very optional)

  * This guide will walk through all the actual code in the backend, core, frontend, and identity repos (note it’s the **root** identity repo, not the deso-workspace one, which is just a wrapper).<br>
  * If you want to learn how one of the most advanced blockchains in the world functions at the core level, this guide is for you!

* [Understand the bigger vision](https://docs.deso.org/about-deso-chain/readme)
  * DeSo is about more than just moving money and content around. If we’re successful in our mission, we will fundamentally change how information is shared on the internet.\
    \
    Just by building on DeSo, you are now a part of this movement toward a more open and free world, and this doc will tell you all about it!

### Using DeSo in an Existing App (Optional)

The rest of this tutorial will focus on creating a new app from scratch, rather than modifying an existing app.

That said, if you would like to use DeSo in an existing app, then all you need to do is `npm install` the [deso-protocol SDK](https://www.npmjs.com/package/des-protocol).\
\
This will then allow you to `login()` users, sign transactions on their behalf, broadcast those transactions to the blockchain, and much more.

```
npm i deso-protocol
```

In what follows, we will show all the different ways to use this library by setting up an example app, and adding functionality to it.<br>

### Example App Setup (Recommended)

Once your IDE is loaded up with all the code you need, the next step is to get the example app up and running locally.\
\
The idea is that, once you get the example app running, you can use it as a starting point, and start modifying it into the **real** app you’re trying to build.

To get the example app up and running, simply follow the steps from the README on the example app’s GitHub.

<https://github.com/deso-protocol/deso-examples-react>

Once you’re done, you should be able to visit [localhost:3000](http://localhost:3000) in an Incognito tab and see the following. We recommend you load it up in Incognito to avoid cluttering your main wallet:

<div><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a3c22fa4-8cfa-407e-93bc-00f12eca261d/Untitled.png" alt=""> <figure><img src="/files/hDHgxTNzhZno6J7dbNst" alt=""><figcaption><p>localhost:3000</p></figcaption></figure></div>

Once your app is running, click the “Sign and Submit Transaction” tab, and go through the process of logging in and creating a post.\
\
This is implicitly exposing you to a `configure()` setup call, a `login()` flow, a transaction construction, and a call to `signAndSubmitTx`.\
\
As we will discuss, these basic building blocks will be pretty much all you need to do **anything** on DeSo, from basic social things to building a breakthrough order-book exchange or NFT marketplace!

### Tip for creating lots of test accounts

As you start developing on DeSo, you will quickly find yourself in need of creating new accounts with starter $DESO in them.\
\
Your phone number will work for getting through the login flow for about ten tries, but after that, it will stop working, and you’ll still want an easy way to test your flows.

While there is a [***testnet***](https://test.deso.org) flow that advanced developers use, the easiest way to test your login flows repeatedly is **send** starter DeSo to your wallet, rather than going through the phone number flow (and this is what most DeSo devs do on testnet as well).

To do this, go through the following steps:

* Create a “master” account either on [wallet.deso.com](http://wallet.deso.com) or on an app like [diamondapp.com](http://diamondapp.com) that you’re going to use as your main one. This could be your **actual** DeSo profile, and you would probably want to do this in a non-Incognito window so that it sticks around.<br>
* Buy a small amount of DeSo either on [Diamond](https://diamondapp.com), [Openfund](https://openfund.com), [wallet.deso.com/buy](http://wallet.deso.com/buy), [megaswap.xyz](https://megaswap.xyz/), or on Coinbase. You only need around $1 worth, and you can use fiat, Bitcoin, Ethereum, Solana, USDT, and USDC.<br>
* Once you have \~$1 of DeSo in your main account, load up your wallet in a separate browser window on any of the previously mentioned apps (e.g. Diamond, Openfund, etc…).<br>
* Now, in an incognito window, open up [localhost:3000](http://localhost:3000) to start your login flow “testing.”
  * You will want to run these tests in Incognito so that your wallet doesn’t get cluttered with lots of throwaway accounts.<br>
* Click the login button to create a new account.&#x20;

  ![](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/68a17219-cc86-46d2-8736-b470e3bc6af5/Untitled.png)
* The fastest way to test your login flow is to use “Sign up with DeSo seed” to generate a fresh account. We on the core team run through this flow all the time because it’s quicker and more efficient than resetting our Google or MetaMask accounts. So just click “Sign up with DeSo seed.”
  * Copy and verify the seed. When testing the login flows, there’s not really a need to save the seed because it’s usually just a throwaway account.<br>
* You should reach this page with a couple of clicks:

<div><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2efb1059-5880-4b31-ac3f-ce3505fab857/Untitled.png" alt=""> <figure><img src="/files/mIZnbcU2EucvRtQFkNEE" alt=""><figcaption></figcaption></figure></div>

* Now, instead of using your phone number, click “Buy or Send $DESO Anonymously,” and scroll down to the “Transfer $DESO to your new account” section:

<div><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b52238b8-ff8f-4ebf-9fa3-f664c16f55f0/Untitled.png" alt=""> <figure><img src="/files/yEWRq3JlG0WRAs3DJIMr" alt=""><figcaption></figcaption></figure></div>

* Now, send 0.00001 $DESO from your main account to the test account. It’s only about a hundredth of a penny, and your app will make much more than that when it’s successful don’t worry :)
  * Also, note that it says that you need to send 0.01 $DESO. Ignore that — you can get away with much less.<br>
* Now hit “Refresh” and it should let you through the flow, approve your permissions, and you’ll be good to go!
  * That amount of $DESO is good for about fifty “lightweight” transactions (uploading images and stuff like that costs a bit more).\
    \
    If you want to test flows that are more than that many transactions long, or that require you to upload data, you will want to send a bit more, or graduate to using testnet.<br>

The above is the actual testing cycle that the DeSo devs use to test production deployments after everything is working on testnet.\
\
As you can see, it costs a little bit of $$, but you have to spend money to make money!

As an exercise, try creating a bunch of accounts via this flow just to make sure you’ve gotten the hang of testing.

### Onboarding funds with MegaSwap

[Megaswap](https://megaswap.xyz) is an amazing tool that allows you to onboard users’ funds onto the DeSo ecosystem (it also supports Bitcoin, Ethereum, Solana, USDC, USDT, and the gas-less DesoDollar stablecoin as well).\
\
You can think of it as your “Stripe for Crypto,” and you can add it to your app with just one line of code.\
\
We won’t go into it just yet, but it will be a key way in which users move funds onto your app.

To see examples of MegaSwap in action, check it out at [megaswap.xyz](https://megaswap.xyz), [Diamond](https://diamondapp.com/buy-deso), and [Openfund](https://openfund.com/wallet). Note that Diamond does a one-line [embed](https://megaswap.xyz/#/iframe/docs/v1) while Openfund uses the API documented [here](https://megaswap.xyz/#/api/docs/v1).

<div><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/dc536ea0-d0f8-4f0b-bf88-1620e20e7bb3/Screen_Shot_2023-02-09_at_8.37.51_AM.png" alt=""> <figure><img src="/files/sdwsjCpiG6QlPwkuNal0" alt=""><figcaption><p>MegaSwap.xyz</p></figcaption></figure></div>

## Basic Configuration Options

Once your example app is running, our first step is to modify the permissions that the app is requesting to suit your needs.\
\
We will do this by modifying the call to the identity library (note that in everything that follows, unless stated otherwise, we will use **identity** to refer to the deso-workspace identity wrapper, not the **root** identity repo which does the actual signing and heavy-lifting).

### Transaction Spending Limits

Setting transaction spending limit options will determine what permissions your users will see when logging into your app, and the amount of $DESO your app can spend on their behalf (among other things).

On DeSo, every user gets a **master** or ***owner*** keypair generated for them when they create an account for the first time, which happens automatically via the `login()` flow that you went through above and that we’ll talk about shortly.

This ***owner*** key is able to sign ***any*** transaction on behalf of the user, including spending ***all*** of their money, and transferring **all** of their NFTs or tokens, **which is scary!**

Naturally, it wouldn’t be a good idea to give every app the user interacts with direct access to this key.

But we also don’t want to make users have to ***approve*** every single transaction that an app wants them to do.

Can you imagine using Twitter if every like and comment required an annoying approval popup?

The solution is to allow apps to generate **subkeys,** which we refer to as ***derived*** *keys*, that have a limited set of permissions approved by the ***owner*** key.

The flow for generating a derived key and getting these permissions approved for your app is something that happened automatically in the login flow you did above, and it looks as follows:

* User creates an account for the first time, generating an ***owner*** public/private keypair that is stored in the **root** identity enclave (this is stored locally in the browser, but in a distinct **iFrame** that is not directly accessible to apps).

  * This is done via a simple call to `login()`, as the example app does [here](https://github.com/deso-protocol/deso-examples-react/blob/4abfdf739b38b3318d524aa713b85bebc1d196a1/src/routes/sign-and-submit-tx.jsx#L21).

* User gets some starter $DESO to cover gas, either by entering their phone number or buying some. The Identity popup supports this natively, and your users will automatically have this starter $DESO when the `login()` call returns successfully, as it does in the example app [here](https://github.com/deso-protocol/deso-examples-react/blob/4abfdf739b38b3318d524aa713b85bebc1d196a1/src/routes/sign-and-submit-tx.jsx#L24).<br>

* App generates a ***derived*** key, which can just be any random keypair, and a distinct transaction granting this derived key certain permissions, e.g. the ability to post 3 times on the user’s behalf.
  * The derived key is generated in the call to `login()` referenced earlier, and it’s saved and managed by the Identity library, so you don’t have to really worry about it.<br>
  * The transaction granting the derived key the permissions you want is **also** automatically generated via `login()`, and you can specify exactly which permissions you want to ask the user for by calling `configure()` once at the beginning of your app.\
    \
    The example app shows you exactly how to do this in the root component [here](https://github.com/deso-protocol/deso-examples-react/blob/e9956588e6a509321bf386eec504c46dd3fd679e/src/routes/root.jsx#L12).<br>

* Once the derived key approval transaction is generated, the Identity wallet can prompt the user to ***approve*** it, thus signing the transaction with the user’s ***owner*** public key.
  * This all happens automatically in the `login()` call for you.<br>

* Once an approve txn is signed by the user’s owner public key, it can be ***broadcast*** to the DeSo blockchain, which then gives the ***derived*** key the desired permissions.
  * This all happens automatically in the `login()` call for you.<br>

* The app can then happily sign transactions on the user’s behalf, without the user having to worry about the app stealing their funds (also known as getting **rug-pulled** or **rugged**).<br>

* If you ever want to ***upgrade*** the permissions your app has requested from the user, you can do this using a call to `identity.requestPermissions()`, as the example app shows [here](https://github.com/deso-protocol/deso-examples-react/blob/4abfdf739b38b3318d524aa713b85bebc1d196a1/src/routes/sign-and-submit-tx.jsx#L45). \
  \
  When you do this, the Identity library automatically handles the construction, signing, and broadcasting of the derived key approval transaction for you.<br>

* After you have the permissions you need, you can now start constructing, signing, and broadcasting **real** transactions on behalf of the user.
  * The example app shows you how to construct a submit-post transaction using the backend API available at [node.deso.org](http://node.deso.org) in this code snippet [here](https://github.com/deso-protocol/deso-examples-react/blob/e9956588e6a509321bf386eec504c46dd3fd679e/src/routes/sign-and-submit-tx.jsx#L61).\
    \
    Signing and broadcasting the transaction to the network is handled by the library. You only need to pass the data you want to be stored in the transaction to the `submitPost()` call.

Once you get your head around it, the process for doing **anything** on DeSo is really quite simple. \
\
First, you get the permissions you need from the user, then you construct, sign, and submit a transaction to the chain, which the deso-protocol SDK makes very simple for you.

### Unlimited Permissions

Although we will normally want to ask for a sober number of transactions, there are times where devs want to loosen the constraints on their apps, and we show how to do this below.

Below we ask users for permission to create an *unlimited* number of posts and make an *unlimited* number of transfers until they meet the global limit of 1 $DESO.

```jsx
import { configure } from 'deso-protocol';

configure({
  spendingLimitOptions: {
    // NOTE: this value is in Deso nanos, so 1 Deso * 1e9
    GlobalDESOLimit: 1 * 1e9 // == 1 Deso
    // Map of transaction type to the number of times this derived key is
    // allowed to perform this operation on behalf of the owner public key
    TransactionCountLimitMap: {
      BASIC_TRANSFER: 'UNLIMITED', // Sending/receiving DESO is a "basic transfer"
      SUBMIT_POST: 'UNLIMITED',
    },
  }
})
```

{% hint style="info" %}
💡 You’ll want to make sure you call **configure** prior to calling any other identity methods.
{% endhint %}

Note that even though we approve an unlimited number of **basic transfer** transactions in the above configure() call, we cannot take more than 1 $DESO from the user’s wallet before we have to popup an approval again.\
\
This is a good thing for the user!

While you’ll typically want to ask for specific permissions in a production app, it is possible to ask for unlimited **god-mode** access for prototyping or quickly testing things.\
\
This example requests approval for unlimited access.

```jsx
import { configure } from 'deso-protocol';

identity.configure({
  spendingLimitOptions: {
    IsUnlimited: true
  }
})
```

### App Name

appName is used to identity the app that issues login keys. This can be used to group and identify derived keys that have been issued by a given app. If you don’t set the appName, the domain name your app is running on will be used by default.

```jsx
import { configure } from 'deso-protocol';

identity.configure({
	**appName: 'My Cool App',**

	spendingLimitOptions: {
    IsUnlimited: true
	}
})
```

Soon, users will be able to easily see all the apps they’ve used, and what permissions they’ve granted them (this is why setting a good app name is helpful!). Users will also be able to disable permissions from one unified dashboard.

## All DeSo Transactions

The example app shows a clear example of getting permissions, logging in a user, and constructing+signing+broadcasting a SubmitPost transaction. \
\
But what else can you do with DeSo?

Once you understand this pattern, all that’s really left to do is learn about all the different transaction types that DeSo supports, and all of their various parameters.\
\
There are several resources you can lean on for this:

* The [deso-protocol js/ts SDK](https://github.com/deso-protocol/deso-workspace/tree/beta/libs/deso-protocol#transactions-writing-data-to-the-blockchain). The deso-protocol SDK makes creating, signing, and broadcasting transactions simple and abstracts away most of the complexity.\
  \
  You can see an exhaustive list of the transaction types it supports [here](https://github.com/deso-protocol/deso-workspace/tree/beta/libs/deso-protocol/src/lib/transactions).\
  \
  Each transaction helper is documented with a link to the relevant backend api documentation which we’ll discuss next.<br>
* [DeSo Docs](https://docs.deso.org/deso-backend/construct-transactions). The DeSo docs are currently going through a major overhaul, and the Identity library, which allows you to construct, sign, and submit transactions very easily, did not exist at the time the ***current*** docs were written.\
  \
  That said, the docs linked here do a good job of documenting **most** of the transactions that are available to be called, along with the parameters they accept. Below are some caveats:<br>
  * Certain newer transaction types are missing because it takes time to update them. To see the full list of transactions that are supported at any given time, you should always refer to the actual open-source code.<br>
    * The TxnType list in [network.go](https://github.com/deso-protocol/core/blob/main/lib/network.go#L205) in the core repo shows the full list of raw transactions that you can construct, sign, and submit to the DeSo blockchain using the identity library.<br>
    * Then, to figure out how to actually ***construct*** the transactions, and what parameters you can pass to each endpoint, you can check [the list of RoutePath variables](https://github.com/deso-protocol/backend/blob/main/routes/server.go#L40) in the backend repo (which includes ***getters*** like fetching all of a user’s posts, etc…). \
      \
      Generally, you should be able to swap out the URL in the example app for submitting a post shown [here](https://github.com/deso-protocol/deso-examples-react/blob/4abfdf739b38b3318d524aa713b85bebc1d196a1/src/routes/sign-and-submit-tx.jsx#L59) with ***any*** of the transaction-related RoutePaths in that file to construct the transaction that you want.<br>
  * In the docs and in the code you will notice a reference to “DAO Coins” and a “DAO Transactions API.”\
    \
    We recently renamed this primitive from “DAO Coins” to “DeSo Tokens,” but this change is not yet reflected in our docs or in the code yet. DeSo Tokens, formerly known as “DAO Coins,” are an ERC-20-like coin that you can mint/burn/trade on-chain, and this is the core primitive that powers [Openfund and its order-book exchange](https://openfund.com/trade/Openfund) (aka the DeSo DEX).\
    \
    Just bear in mind that you may see things referred to interchange-ably as “DeSo Tokens” and “DAO Coins,” but they are the same thing.<br>
  * You will see a reference to Creator Coins here or there. These are a different type of primitive that is ***distinct*** from DeSo tokens. Instead of being arbitrarily mint-able, and trade-able on the DeSo DEX, they are locked onto a ***bonding curve***, and are minted and burned according to a fixed formula.\
    \
    Although they are easier to use in many ways, they pre-date DeSo Tokens, and we recommend you only use them if you really know what you’re doing.<br>
  * You will notice that access groups, aka the DeSo Chat Protocol, are not in the docs but are listed in the core and backend repos.\
    \
    This is because they are an awesome cutting-edge feature that you can play with on testnet [here](https://ln.deso.run/), and soon on [chat.deso.com](http://chat.deso.com).<br>
* Open the inspector on [Diamond](https://diamondapp.com), [Openfund](https://openfund.com), [node.deso.org](https://node.deso.org), or [our chat prototype](https://www.notion.so/Building-on-DeSo-bf28fce2fe0b4bac9228299114f39fff) (soon [chat.deso.com](https://chat.deso.com)).
  * Although they don’t leverage the recently-launched Identity library, Diamond and Openfund can be useful in demonstrating how to ***construct*** certain transactions, and in illustrating the **parameters** available during construction.\
    \
    They can also illustrate ***getters*** like how to fetch all of a user’s posts.
    * To look at their transactions, simply right-click and hit “Inspect” anywhere on the page, then open the “Network” tab.&#x20;
    * With the network tab open, perform an action like submitting a post and watch the output on the Network tab.
    * Click on the transaction construction call, which should generally be easy to spot. In this case it’s clearly the `submit-post` call.
    * After clicking on this line, you can see the headers that were sent as well as the payload. Here you can see there are many other parameters that one could add to a post. You can also see what it looks like to add an image or a video to a post.<br>
  * Diamond supports the full “Twitter” feature set as well as the full NFT feature set so it’s good for playing with social and NFT types of transactions. It also supports v1 messaging, though this is going to be replaced by access groups, which are fully implemented in the chat prototype.<br>
  * Openfund supports the full DeSo Token feature set, as well as all of the DeSo DEX transactions. So it’s good for anything token-related you might want to do.\
    \
    This being said, [node.deso.org](http://node.deso.org) has an extremely simple “DAO Coin” tab that shows minting, burning, and transferring DeSo Tokens (formerly known as DAO Coins), so it might be better to start there and then work your way up to Openfund.<br>
  * All of the apps have a pretty solid wallet UI, though the Openfund wallet may be a bit more complete than the Diamond wallet.

## Next Steps: A Simple Jackpot App

Now that you know everything you need to know about constructing and submitting transactions to the DeSo blockchain, you can build a **real** app that leverages the full power of crypto with **just** your web2 knowledge.

Below are some recommended exercises that you can do fairly quickly to get up to speed:

* **Show all of a user’s posts on the example app.**
  * The example app allows you to submit posts but it doesn’t show you the posts that you’ve already got on the DeSo blockchain.\
    \
    To figure this out, you can open the inspector on a [Diamond profile page](https://diamondapp.com/u/nader) and look for the `get-posts-for-public-key` call.\
    \
    Once you have that, it should be straightforward to put the call into the example app and show the posts.<br>
* **Add a profile update flow to the example app.**
  * You can do this by inspecting Diamond or [wallet.deso.com](https://wallet.deso.com) profile update flow, and making the right construction call in the example app (plus some basic form fields).<br>
* **Show users’ DeSo and token balances in the example app.**
  * You can inspect the [wallet page](https://wallet.deso.com/?tab=tokens) to get this integration.<br>
* **Integrate** [**MegaSwap**](https://megaswap.xyz) **into your example app so people can add funds to their wallet balances.**
  * This should be as simple as dropping the single-line MegaSwap iFrame from the “Embed” tab on the MegaSwap homepage, and inserting the user’s DeSo public key.<br>
* **Add a simple “jackpot” functionality to the example app.**
  * To practice moving money around, add a simple button to the example app that takes 0.1 DESO from the user and sends it to a wallet you control.<br>
  * Then, make it so that if no user pushes the button for a whole hour, the most recent user to push the button wins all of the funds in the wallet (i.e. they get the jackpot).<br>
  * Such an experiment was executed by Fomo3d with great success, and resulted in a jackpot of over $3 million. No reason why it couldn’t be done again :)<br>
  * You can obviously play with the mechanics however you want. For example, you could even ditch the jackpot idea and alternatively just give the user 10x their money back with 9% probability (thus collecting a 1% rake on everyone who pushes the button). It’s really up to you. Just play around and have fun.<br>
* You can add a leaderboard showing the profiles of the users who have spent the most money pushing the button (or whatever) to make it more social and fun.


# Node Architecture Overview

*TODO: This was written when DeSo was running on Proof of Work, but it's still a great reference. See* [*here*](https://revolution.deso.com) *for info about Proof of Stake upgrades.*

## Introduction: The DeSo Repos

The code powering a DeSo node like node.deso.org consists of four repos: frontend, backend, core, and identity. When you run a DeSo node using this code, you get access to all of the blockchain data from the beginning of time (late 2020).

The DeSo Foundation prepared sample code that you can check out, and you can run it to quickly **create** **your own social network**!

* **Core Protocol:** [github.com/deso-protocol/core](https://github.com/deso-protocol/core)
  * This is a Golang repo that contains all of the "consensus" code behind DeSo. It's meant to be kernel that's embedded as a library into projects that want to build on the DeSo firehose.<br>
* **Backend:** [github.com/deso-protocol/backend](https://github.com/deso-protocol/backend)
  * The backend repo embeds core as a library and exposes a rich API on top of it to support transaction construction, submitting transactions to the blockchain, storing user data, and more. In some sense, it's the first "reference" app built on the core DeSo blockchain.<br>
* **Frontend:** [github.com/deso-protocol/frontend](https://github.com/deso-protocol/frontend)
  * This is an Angular **reference** app that is similar to the front-end of diamondapp.com. It uses the API exposed by the backend repo to support all of its queries.<br>
* **Identity:** [github.com/deso-protocol/identity](https://github.com/deso-protocol/identity)
  * This is a lightweight embeddable app that gets loaded as an iFrame in the frontend Angular app to handle all signing functions.

Below is a simple diagram that shows visually how these repositories fit together:

![](/files/qi8S2FiCZQ1CJTkaYcTU)

## Overview of the architecture

We think the easiest way to understand the architecture is to describe how a node syncs with other nodes, and then to walk through key code-paths with pointers to functions and line numbers.&#x20;

We use the following commit hashes to refer to the code:

* **Core:** [135c03a958039423ac2c775cb83eb2a41d903511](https://github.com/deso-protocol/core/tree/135c03a958039423ac2c775cb83eb2a41d903511)
* **Backend:** [96d24569a7b4581644a330be168c441c948d9040](https://github.com/deso-protocol/backend/tree/96d24569a7b4581644a330be168c441c948d9040)
* **Frontend**: [c1363f7fb0239a835b1f2c91d395c8e2d22cbb8f](https://github.com/deso-protocol/frontend/tree/c1363f7fb0239a835b1f2c91d395c8e2d22cbb8f)
* **Identity**: [665281c54b8136a5b8965fb907aac7419ac4c735](https://github.com/deso-protocol/identity/tree/665281c54b8136a5b8965fb907aac7419ac4c735)

### The node’s main loop

* The entrypoint to everything the node does is [`main.go`](https://github.com/deso-protocol/backend/blob/96d2456/main.go#L15). It's better to start tracing from the backend repo's main rather than the core repo's main, since the core repo is mainly intended to be used as a library. Moreover, since backed uses the core repo as a library, we will hit all of the core functionality by starting here anyway.<br>
  * There is a lot of indirection in main introduced by the fact that we are using Viper to manage our command-line flags. When the backend binary is run, a command is passed, such as "run," which triggers [a `Run()` function defined in the cmd package](https://github.com/deso-protocol/backend/blob/96d2456/cmd/run.go#L23).<br>
  * All available commandline flags can be viewed [in the `init()` function](https://github.com/deso-protocol/backend/blob/96d2456/cmd/run.go#L45). Some of these flags are initialized in [`LoadConfig()`](https://github.com/deso-protocol/backend/blob/96d2456/cmd/run.go#L25) at the beginning of `Run()`.<br>
    * Note the core repo's flags are effectively imported into backend. This allows for maximum composability, whereby someone can include the core repo and get all of its functionality embedded into their binary for free.<br>
  * Once you get into the [`Run()`](https://github.com/deso-protocol/backend/blob/96d2456/cmd/run.go#L23) function, everything the node does can be traced explicitly. We will be walking through some of the key codepaths below<br>
* When a node [starts up](https://github.com/deso-protocol/backend/blob/96d2456/cmd/node.go#L31), it looks for peers that it can download blocks and transactions from. There are two main ways a node finds peers:<br>
  * DNS bootstrapping. All peers scan domains of the form `deso-seed-*.io` to see if any valid peers are available. The function that does that is [`addSeedAddrsFromPrefixes()`](https://github.com/deso-protocol/core/blob/135c03a/cmd/node.go#L303) and the list of "prefixes" that are scanned is defined in [`constants.go`](https://github.com/deso-protocol/core/blob/135c03a/lib/constants.go#L479).<br>
    * Because it would cost O($1M) to buy all of the seeds, and because a node only needs one valid sync peer in order to thwart an "eclipse" attack, and because a node can iterate over tens of thousand of DNS records per second, and because DNS seeds can be changed by node operators if a particular prefix is monopolized, we think this is a safe way to find initial peers.<br>
  * Commandline flags. `--connect-ips` means a peer will connect to the specified peer and nothing else. `--add-ips` means these peers will be added to the list of things that the peer is going to try and connect to.\
    \
    When we spin up new nodes, we often use `--connect-ips` with a trusted node because it's easier than bootstrapping from the sea of nodes that are running in the wider internet.<br>
* The ConnectionManager is responsible for managing all connections with peers. It's initialized using a [`Start()`](https://github.com/deso-protocol/core/blob/135c03a/lib/connection_manager.go#L769) function that is kicked off in main.go. Tracing the code starting from this function is a great way to understand how connections with peers are established and maintained.<br>
* When the ConnectionManager connects to a peer, it does a "version negotiation" similar to Bitcoin. This happens in [`ConnectPeer()`](https://github.com/deso-protocol/core/blob/135c03a/lib/connection_manager.go#L372). If the peer passes this version negotiation, then the peer is passed off to `server.go` via a "newPeerChan." server.go is then responsible for doing higher-level interactions with the peer.<br>
  * `server.go` is started using a [`Start()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1720), which is a good place to start tracing through it. `server.go` can be thought of as the "main loop" for the node.\
    \
    It is basically a single for{} loop that all peers and services are adding messages to. See [`messageHandler()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1515) to see this "main loop" in action.<br>
  * server.go processes two types of messages conceptually. [Control messages](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1471) and [peer messages](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1489), both via messageHandler.<br>
    * Peer messages just contain messages that came from one of the peers that the node was connected to. You can see there aren't very many of them, and they're fairly straightforward.<br>
    * Control messages are basically notifications about things that happened internally to the node. For example, a new peer connected or a new peer disconnected.<br>
* When a peer is connected, server.go gets a NewPeer or [`MsgDeSoNewPeer`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1474) control message from the ConnectionManager and handles it in [`_handleNewPeer()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L775). This is typically the "starting point" for server.go<br>
  * If the peer is a valid one, then server.go will accept this peer as a "sync peer" in [`_startSync()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L709), and it will send it a GetHeaders or [`MsgDeSoGetHeaders`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L765) message to start syncing headers and blocks from it.<br>
  * The initial sync for a node is currently completely single-threaded. A sync peer is found and other peer messages are largely ignored until the node has downloaded up to the last 24 hours worth of blocks.<br>
* Below are the steps to syncing with a peer, which can be traced by following the functions in server.go:
  * ConnectionManager passes a `MsgDeSoNewPeer` message to server.go, which is processed in [`messageHandler()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1515).<br>
  * Choose a remote peer as a syncPeer in [`_startSync()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L685). Call this the "remote peer."<br>
  * Send the remote peer [`MsgDeSoGetHeaders` in `_startSync()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L765)<br>
  * Remote peer replies to the `MsgDeSoGetHeaders` with a [`MsgDeSoHeaderBundle` in `_handleGetHeaders()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L439).<br>
    * Note that a "header locator" similar to Bitcoin is used to determine which headers are needed.<br>
  * Node processes the `MsgDeSoHeaderBundle` at [`_handleHeaderBundle()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L526) and responds with different messages depending on how synced the peer is.<br>
    * If more headers are required, it sends [another `MsgDeSoGetHeaders`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L692). Note that headers are requested until the number of headers in the [latest HeaderBundle is < `MaxHeadersPerMsg`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L604). This is how the node knows that it's downloaded all the headers the remote peer has for it.<br>
    * If the node has exhausted the peer's headers then it downloads blocks until it has a block for every corresponding header that the peer sent it. This is exactly the same as the "headers-first" synchronization that Bitcoin does. The `MsgDeSoGetBlocks` message is sent in [`GetBlocks()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L480).<br>
    * Processing a block happens in [`ProcessBlock()`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L1494), which is a great function to trace through. It calls [`ConnectBlock()`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L1766), which calls ConnectTransaction on each transaction, which we'll discuss later.<br>
    * Once the node has all the headers it needs from the peer, and if the node has downloaded and validated all the blocks from this peer, then the node is fully synced.<br>
      * Once we get to this state, the node listens to INV messages from all of its peers. If it sees an INV message for a new block that it doesn't have yet, then it will send the peer a `GetHeaders` request, which will kick off this headers-first process for the single missing header/block.<br>
* Once the node has gotten through this loop, it is fully synced and in a "steady-state." At this point, the node listens for INV messages from its peer to update its state. `INV` messages or `MsgDeSoInv` are processed via [`messageHandler()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1515) just like everything else.\
  \
  `INV` messages can be for a block, as mentioned previously OR for a transaction. Below is the case for a transaction `INV`:<br>
  * Note that some "handle" functions are defined in peer.go rather than server.go. When this is the case, the server.go [`_handlePeerMessages()`](https://github.com/deso-protocol/core/blob/135c03a/lib/peer.go#L1489) function will just enqueue the message for the peer's thread to process it.\
    \
    This is done in order to move processing into another thread for efficiency reasons (not doing this would cause server.go to be \*too\* single-threaded). Here you can see the `_handleInv()` in `server.go` [delegate the call](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1306) to peer.go, and here you see peer.go [dequeuing it to process it](https://github.com/deso-protocol/core/blob/135c03a/lib/peer.go#L562).\
    \
    Note that there are several messages that are delegated in this way, all defined in the [`StartDeSoMessageProcessor()`](https://github.com/deso-protocol/core/blob/135c03a/lib/peer.go#L530) function.<br>
  * If the node is missing a transaction that it received an INV for, it sends a GetTransactions or [`MsgDeSoGetTransactions`](https://github.com/deso-protocol/core/blob/135c03a/lib/peer.go#L440) message to the peer.<br>
  * This triggers the node's [`_handleGetTransactions()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1309) function in server.go, which results in a `TransactionBundle` or `MsgDeSoTransactionBundle` [being sent back](https://github.com/deso-protocol/core/blob/135c03a/lib/peer.go#L217).<br>
  * The node receives the transaction bundle [here](https://github.com/deso-protocol/core/blob/135c03a/lib/peer.go#L218) and processes each transaction in [`_processTransactions()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1334) in `server.go`.<br>
    * When a transaction is processed in `server.go`, it is basically just calling [`processTransaction()`](https://github.com/deso-protocol/core/blob/135c03a/lib/mempool.go#L1887) in `mempool.go`.\
      \
      If the transaction is valid then it will be added to the mempool, and if not then it will be rejected. In order to validate a transaction, mempool uses the previously mentioned [`ConnectTransaction()`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L6043) function defined in `block_view.go`.<br>
* Now we understand how a node syncs initial blocks, and how it accepts new blocks and transactions in the steady-state. The next step is to understand how blocks are created and mined:<br>
  * `block_producer.go` runs in a continuous loop kicked off via a [`Start()`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_producer.go#L522) function called in main.go. `Start()` calls [`UpdateLatestBlockTemplate()`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_producer.go#L476) at regular intervals to create new blocks for miners to mine. This is a great function to trace.<br>
  * Function [`_getBlockTemplate()`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_producer.go#L110) contains the logic for constructing a new block. It basically does the following:
    * Add txns from the mempool to the block until the block is full.
    * Compute the fee, merkle root, etc.<br>
  * Newly-created "block template" is added to `recentBlockTemplatesProduced` in [`AddBlockTemplate()`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_producer.go#L376).<br>
  * `block_producer.go` just produces block templates, but it's up to miners to compute winning hashes. That happens via a remote process as follows:<br>
    * Every node exposes two functions via JSON API: [`GetBlockTemplate()`](https://github.com/deso-protocol/backend/tree/main/routes#L10372) and [`SubmitBlock()`](https://github.com/deso-protocol/backend/tree/main/routes#L10445). The URL paths for these and all other API functions can be seen [here](https://github.com/deso-protocol/backend/tree/main/routes#L9638) and [here](https://github.com/deso-protocol/core/blob/135c03a/lib/api.go#L63) (the latter powers the block explorer).<br>
    * Miners run [`remote_miner_main.go`](https://github.com/deso-protocol/core/blob/135c03a/remote_miner_main.go) and connect to any node they want via a flag. This can be their own local node or a remote node like node.deso.org. `remote_miner_main.go` will continuously call `GetBlockTemplate()` on the chosen node and hash it until it's found a block.\
      \
      Once it has found a winning hash, it calls `SubmitBlock()`, which then causes the node to process it and broadcast it to the rest of the network.<br>
      * Because all nodes expose `get-block-template`, all nodes can be used to mine blocks in this way. Miners generally don't need to do anything other than point to a valid DeSo node somewhere on the network.<br>
    * Note that we are currently working on increasing the nonce size to 64 bits up from 32 bits. This will result in ExtraNonce being basically deprecated, and will make `GetBlockTemplate()` much faster because it won't have to copy a block.<br>
  * Once a block has been submitted via SubmitBlock, it is then relayed to other peers via the INV mechanism described previously. This happens as follows:
    * [`SubmitBlock()` in `miner.go`](https://github.com/deso-protocol/backend/blob/47bcc8af71b039f857bd949fcea94bfbed8b57e8/routes/miner.go#L125) calls [`ProcessBlock()`](https://github.com/deso-protocol/backend/blob/47bcc8af71b039f857bd949fcea94bfbed8b57e8/routes/miner.go#L177)<br>
    * `ProcessBlock()` notifies core's `server.go` that a block was connected by calling [`_handleBlockMainChainConnectedd()`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L1854)<br>
    * `_handleBlockMainChainConnectedd()` updates the mempool using [`UpdateAfterConnectBlock()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1078), which removes transactions from the mempool that have been mined into the block<br>
    * `ProcessBlock()` notifies `server.go` again by [enqueing a `MsgDeSoBlockAccepted`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L2135) message at the end, triggering a call to [`_handleBlockAccepted`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1127).
      * This creates an `INV` for the new block that gets relayed to all the peers who will then request it from this node.<br>
* There is one more important thread that a node runs at startup, which is the BitcoinManager thread defined in `bitcoin_manager.go`. Like everything else, it has a [`Start()`](https://github.com/deso-protocol/core/blob/135c03a/lib/bitcoin_manager.go#L2105) function that is kicked off in `main.go` via `server.go` (called [here](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1741). It works as follows:<br>
  * It looks for a Bitcoin peer and connects to it through [`_getBitcoinPeer()`](https://github.com/deso-protocol/core/blob/135c03a/lib/bitcoin_manager.go#L1741).<br>
  * It sends the Bitcoin peer a [`GetHeaders`](https://github.com/deso-protocol/core/blob/135c03a/lib/bitcoin_manager.go#L1985) and kicks off a single-threaded main loop with its peer [here](https://github.com/deso-protocol/core/blob/135c03a/lib/bitcoin_manager.go#L2001).<br>
  * It downloads headers until it is fully synced with the Bitcoin peer.
    * All we really need from a Bitcoin node is its header chain.
    * The headers are used to validate [BitcoinExchange](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L2647) transactions when calling `ConnectTransaction()` in either [`ProcessBlock()`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L1688) or [`processTransaction()`](https://github.com/deso-protocol/core/blob/135c03a/lib/mempool.go#L999). A BitcoinExchange transaction is only valid if it has a merkle proof attached to it that has a valid Bitcoin header hash as its root. More on this later.<br>
  * In addition to the header chain, new blocks are downloaded from the Bitcoin node in order to extract valid BitcoinExchange transactions from them. Basically, any transaction that sends Bitcoin to the sink address, [defined here](https://github.com/deso-protocol/core/blob/135c03a/lib/constants.go#L506), is recognized as being able to print DeSo on the Bitcoin chain.<br>
    * Blocks are downloaded from the Bitcoin peer whenever a new header is received from the peer [here](https://github.com/deso-protocol/core/blob/135c03a/lib/bitcoin_manager.go#L1414) and [here](https://github.com/deso-protocol/core/blob/135c03a/lib/bitcoin_manager.go#L1333).<br>
    * You can see how the extraction of a BitcoinExchange transaction works [here](https://github.com/deso-protocol/core/blob/135c03a/lib/bitcoin_manager.go#L1632).<br>
  * Like other services, whenever the BitcoinManager gets some new transactions or headers, it notifies server.go by adding a message that will be processed by `messageHandler`. This happens [here](https://github.com/deso-protocol/core/blob/135c03a/lib/bitcoin_manager.go#L1098).<br>
  * The BitcoinManager does some other things, like for example it is used to broadcast BitcoinExchange transactions to many peers at once [here](https://github.com/deso-protocol/core/blob/135c03a/lib/bitcoin_manager.go#L1806). But its main purpose is to download the Bitcoin header chain and, to a lesser extent, to download new blocks and extract valid BitcoinExchange transactions from them.<br>
  * Note also that using a single Bitcoin peer may seem insecure, but because the node checks the minimum work is above a certain threshold, it's generally not an issue.\
    \
    Additionally, nodes that run the main protocol code are pointed at specific trustworthy Bitcoin peers using [--bitcoin\_connect\_peer](https://github.com/deso-protocol/core/blob/135c03a/cmd/config.go#L91)

### Seed creation and transaction construction

Below we trace how seeds and transactions are created while giving detail on their format and how validation works.

* First, a user lands on an app like [Diamond](https://diamondapp.com), which is the Angular frontend.<br>
  * All the API endpoints for the frontend are defined in a single file called [backend\_api\_service.ts](https://github.com/deso-protocol/frontend/blob/96bdf0c/src/app/backend-api.service.ts)
    * All the routes are defined [here](https://github.com/deso-protocol/frontend/blob/96bdf0c/src/app/backend-api.service.ts#L12).<br>
  * They all hit corresponding API endpoints defined on the node's JSON API, which is fully defined in [frontend\_server.go](https://github.com/deso-protocol/backend/tree/main/routes).<br>
    * All the routes are the same as the ones defined in `backend_api_service.go` and are defined [here](https://github.com/deso-protocol/backend/tree/main/routes#L9435) and configured [here](https://github.com/deso-protocol/backend/tree/main/routes#L9500).<br>
    * When a node starts up it opens up three ports: A "web" port that serves the Angular app, a "protocol" port that is used to connect with peers and process all blockchain-related messages, and an "API" port that is used to handle requests from the Angular app.
      * By default these ports are: 4002=Angular app, 17001=JSON API, 17000=protocol port
      * Note that the “web” port is deprecated in favor of running the frontend Angular app as a stand-alone service. So very soon a node will only have a JSON API port and a protocol port.<br>
    * Anytime the angular app needs to do something like construct a transaction or download the data for a user, it uses the API port. The JSON API is like "glue" between the blockchain and the frontend.<br>
* Creating and storing the seed
  * When a user hits “Sign Up,” they are taken to identity.deso.org.<br>
    * On identity.deso.org, the user generates a seed phrase and then [hits next](https://github.com/deso-protocol/identity/blob/665281c/src/app/sign-up/sign-up.component.ts#L69).
      * The seed is stored in the `localStorage` of identity.deso.org using a call to [addUser](https://github.com/deso-protocol/identity/blob/665281c/src/app/sign-up/sign-up.component.ts#L75).<br>
    * All of the seed phrases stored in `localStorage` are encrypted using a call to [`getEncryptedUsers()`](https://github.com/deso-protocol/identity/blob/665281c/src/app/sign-up/sign-up.component.ts#L85).<br>
      * The [access level](https://github.com/deso-protocol/identity/blob/665281c/src/app/account.service.ts#L32) of the host is determined. For example, [Diamond](https://diamondapp.com) has “FULL” access. Other nodes will have different access depending on what users have explicitly allowed.<br>
      * If a host has “FULL” access, then an [encryption key](https://github.com/deso-protocol/identity/blob/665281c/src/app/crypto.service.ts#L70) is computed for that host, to be used in a subsequent step.\
        \
        This encryption key is [stored in localStorage](https://github.com/deso-protocol/identity/blob/665281c/src/app/crypto.service.ts#L44) where possible, but for some browsers like Safari it must be stored in a Cookie, which is less ideal but it works.<br>
      * Once an encryption key is generated for the host, it is used to compute an [`encryptedSeedHex`](https://github.com/deso-protocol/identity/blob/665281c/src/app/account.service.ts#L36). Again, this only happens if the node has the FULL access level.<br>
    * Then, if the host has the FULL access level, the encrypted users are sent back to the host (in our case it’s diamondapp.com) by a call to [login()](https://github.com/deso-protocol/identity/blob/665281c/src/app/sign-up/sign-up.component.ts#L84), which then does a [window.postMessage](https://github.com/deso-protocol/identity/blob/665281c/src/app/identity.service.ts#L44) back to the host.<br>
      * Note: This is tab-to-tab communication. diamondapp.com opens identity.deso.org, identity generates the `encryptedSeedHex`, and then sends it back to diamondapp.com. This same process works if you replace diamondapp.com with the host of your own third-party node.\
        \
        The difference is that your third-party node will need to ask the user for permission in order to get encryptedSeedHex sent back to it.<br>
  * Once diamondapp.com has the `encryptedSeedHex`, it uses it to sign things. It does this by calling various operations on an iframe of identity.deso.org embedded within it.<br>
    * /frontend gets an unsigned transaction from the JSON API. Here is an example where it gets [an unsigned SubmitPost transaction](https://github.com/deso-protocol/frontend/blob/96bdf0c/src/app/backend-api.service.ts#L598).<br>
    * Then it calls [`signAndSubmitTransaction`](https://github.com/deso-protocol/frontend/blob/96bdf0c/src/app/backend-api.service.ts#L612), which [sends](https://github.com/deso-protocol/frontend/blob/96bdf0c/src/app/backend-api.service.ts#L270) it to the identity.deso.org iframe via a [postMessage](https://github.com/deso-protocol/frontend/blob/96bdf0c/src/app/identity.service.ts#L84) to call [doSign()](https://github.com/deso-protocol/identity/blob/665281c/src/app/embed/embed.component.ts#L47).<br>
      * Importantly, in order to have identity sign the transaction, diamondapp.com includes the [`encryptedSeedHex` and the transaction hex](https://github.com/deso-protocol/frontend/blob/96bdf0c/src/app/backend-api.service.ts#L271).<br>
    * identity.deso.org then decrypts the `encryptedSeedHex` with the host-specific encryption key, signs the transaction, and returns the signed transaction back. This all happens [here](https://github.com/deso-protocol/identity/blob/665281c/src/app/embed/embed.component.ts#L73).<br>
  * Why is this so complicated? Why send `encryptedSeedHex` back to the host? Wouldn’t it be better to just keep everything in identity.deso.org?<br>
    * The reason for this setup is that iOS devices does not allow identity.deso.org to access persistent `localStorage` when it’s embedded as an `iframe` in diamondapp.com. \
      \
      This is due to Apple’s crusade against third-party cookies. However, Apple does allow identity.deso.org to access its cookies when its embedded as an iframe on diamondapp.com if those cookies are set as first-party cookies.<br>
    * So, what do we do? We push the user to create their seed on identity.deso.org, where we can set an encryption key as a first-party cookie. Then, back on diamondapp.com we store the `encryptedSeedHex`.\
      \
      When signing is needed, the `encryptedSeedHex` is passed to the identity.deso.org iframe, which has access to the encryption key in the cookie, which it then uses to decrypt the `encryptedSeedHex` and sign the transaction.<br>
    * One draw-back of this approach is that cookies are sent to the identity.deso.org automatically when the page or iframe loads. This is not ideal, but that information is useless without the actual seed. Moreover, and critically, cookies are only used on iOS devices.\
      \
      On non-iOS devices, the encryption key is stored in `localStorage`. This means that only iOS devices are subject to this drawback.<br>
    * One other draw-back is that an XSS attack on diamondapp.com or a third-party node could technically give the attacker access to the `encryptedSeedHex`. However, this information is useless without the encryption key stored exclusively in identity.deso.org.<br>
* When a user does any kind of "write" operation in the app, such as submitting a post, liking, or updating their profile, a corresponding endpoint in `frontend_server.go` is called to construct a transaction.\
  \
  That transaction is then returned unsigned, signed by the identity iframe, and then submitted back to core via [`SubmitTransaction()`](https://github.com/deso-protocol/backend/tree/main/routes#L2984).<br>
* As an example, consider [`/send-deso`](https://github.com/deso-protocol/backend/blob/47bcc8a/routes/server.go#L45), which is relatively straightforward:<br>
  * [First, a universal view is fetched.](https://github.com/deso-protocol/backend/tree/main/routes#L2849) More on this later, but it basically gives the endpoint a "union" of the "state" between what's in the mempool and what's in the blocks. For example, if someone sent you DeSo in a txn that's in the mempool, you can use the view to find that UTXO. And if they sent it to you in a txn that's been mined into a block, you can also find it in that view.<br>
  * In order to create the spend transaction, the endpoint needs to find UTXO's for the user. \
    \
    This generally always happens in [`AddInputsAndChangeToTransaction()`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L3033), which is a good function to trace through. We're not aware of any transaction assembly that does not utilize this function for UTXO fetching.<br>
    * The key function is [`GetSpendableUtxosForPublicKey()`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L2268), which generates a universal view that includes txns from the mempool and then returns all UTXO's that are associated with the particular public key. These UTXO's can then be assembled into a transaction.<br>
    * Again, basically all transaction assembly runs through this codepath.<br>
  * Then the transaction is sent back to the frontend and signed.<br>
  * [`SubmitTransaction()`](https://github.com/deso-protocol/backend/tree/main/routes#L2983) is called.<br>
  * The transaction is then validated and broadcasted in [`VerifyAndBroadcastTransaction()`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L226).<br>
    * It does [some pre-validation](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L2155) of the transaction by calling [`ConnectTransaction()`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L6043) on it.<br>
    * If the validation passes then it calls [`BroadcastTransaction()`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L209), which calls [`_addNewTxn()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1023) in server.go, which adds the transaction to the mempool calling [`ProcessTransaction()`](https://github.com/deso-protocol/core/blob/135c03a/lib/mempool.go#L1943).<br>
    * Once the transaction is in the mempool, the node will eventually relay the transaction to its peers via a separate thread running in server.go that's kicked off in `Start()` through [`_startTransactionRelayer()`](https://github.com/deso-protocol/core/blob/135c03a/lib/server.go#L1669).<br>
      * This thread is basically looking at the mempool at regular intervals and sending transactions to peers that they don't already have. This is how a transaction that's generated in the UI makes it to the rest of the network.<br>
  * Once a transaction has gone into the mempool then we're done. It will eventually be mined into a block.<br>
* A note on the [`/burn-bitcoin`](https://github.com/deso-protocol/backend/blob/47bcc8a/routes/server.go#L44) endpoint:<br>
  * This endpoint is called when a user buys DeSo using Bitcoin in the "Buy DeSo" tab. It does the following:<br>
    * Constructs a Bitcoin transaction sending the user's Bitcoin to the "sink" address<br>
    * Broadcasts it to the Bitcoin blockchain<br>
    * Waits some amount of time for the transaction to propagate<br>
    * Checks to see if a double-spend occurred during this interval.<br>
    * If no double-spend was detected, the transaction is added to the DeSo mempool with the expectation that it will eventually mine into a Bitcoin block (and subsequently a DeSo block).<br>
      * The fee is generally set to 2x the "fastest" fee to ensure very high probability that the txn is processed.\
        \
        This is currently set in the frontend, but there is no reason why it can't be re-enforced in either the frontend\_server.go code or in the mempool itself prior to accepting the Bitcoin txn.<br>
    * Once this transaction has been accepted into the mempool, the user can immediately spend it.<br>
      * This means there will be some risk of reversion of the user's transactions if the transaction isn't ultimately confirmed by the Bitcoin blockchain.\
        \
        But we have yet to have someone successfully double-spend against the latest iteration of the double-spend checking logic.<br>
    * BitcoinExchange transactions can also be added to the mempool via relay from other peers.\
      \
      In this case, the node can be set to [ignore unmined Bitcoin transactions from peers](https://github.com/deso-protocol/core/blob/135c03a/lib/peer.go#L224) so there is minimal risk of a double-spend or reversion.<br>
  * Importantly, no matter what the mempool does, the DeSo blockchain will not allow a BitcoinExchange transaction into it without at least one block of work on it.\
    \
    In practice, three blocks of work are required because miners wait for three blocks in order to be safe. This happens via a param called [`MinerBitcoinMinBurnWorkBlocks`](https://github.com/deso-protocol/core/blob/135c03a/lib/constants.go#L504) that is utilized by the block producer.

### Transaction format

* Generally, all important "messages" that need to get sent between peers, most notably `MsgTxn` and `MsgDeSoBlock`, are defined in [`network.go`](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go). They all implement the very simple [`DeSoMessage`](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L208) interface.<br>
* All of these messages have serialization functions called ToBytes() that are defined by us in order to guarantee that all nodes serialize to the exact same bytes. If we were to rely on protobufs of JSON, nodes could get different serialized byte strings for the same messages because these formats do not guarantee consistent serialization across machines.<br>
* Transactions are based on UTXO's. They contain the following:<br>
  * [`TxInputs`](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L2200), which is effectively a list of \<PreviousTxID, index> pairs called [`UtxoKey`](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L2148) where the index refers to the output being spent.<br>
  * [`TxOuptuts`](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L2201), which just specify what amounts are going to which public keys.<br>
  * `TxnMeta`. More on this later<br>
  * [`PublicKey`](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L2215). In DeSo transactions are very simple and only have one public key that can be deemed to be the "executor" of the transaction. The transaction is generally always signed by this public key.<br>
  * [`ExtraData`](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L2221). This is a flexible map that arbitrary data can be added to. It is currently used to support Reposts via [`RecloutedPostHash`](https://github.com/deso-protocol/core/blob/135c03a/lib/constants.go#L944) and [`IsQuoteReclouted`](https://github.com/deso-protocol/core/blob/135c03a/lib/constants.go#L946) params.\
    \
    It can be used to augment a transaction without causing a hard fork, which significantly increases the extensibility of DeSo by the community. For example, one can trivially add a "pinned posts" feature using `ExtraData` without consulting the core DeSo devs about it.<br>
* Note that the map keys of `ExtraData` are [always sorted](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L2158) when serialized so that consistent serialization across machines is preserved even though we're using a map.<br>
* Transaction metadata is used to determine what type of transaction we're dealing with. For each type of transaction in the system, a metadata type is defined that implements the [`DeSoTxnMetadata`](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L299) interface.\
  \
  The full list of transaction types can be viewed [here](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L239). To see descriptions of each one, simply find where that transaction type implements the interface.<br>
  * For example, here is the [`BitcoinExchangeMetadata`](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L2647). You can see it contains a full Bitcoin transaction plus a merkle proof into the Bitcoin blockchain. This is how a node verifies that a particular Bitcoin transaction has a sufficient amount of work on it.

### Transaction validation

* Virtually all transaction validation happens in [`_connectTransaction`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L5022) in `block_view.go`.
* Validation works by applying the transaction to a "view," which is basically a "simulation" of what would happen if the transaction were written to the database, but that doesn’t actually modify the database.\
  \
  This is useful because a view can allow you to "simulate" what would happen if you applied a bunch of transactions to the database in sequence in order to validate whole blocks before ever actually writing anything to the database. And this is exactly what [`ConnectBlock`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L5120) does.<br>
  * A view is basically a "copy on write" system. When a transaction requires something to be written to the database, an in-memory entry is created representing that entry.\
    \
    This generally happens in calls to \_set.\*mappings and \_get.\*, such as [`_setProfileEntryMappings`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L2873) and [`_getProfileEntryForUsername`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L2757).<br>
* If all of the transactions that have been applied to a view appear to be valid, the view can be "flushed" to the database, which writes all of the updates those transactions produced to the database. The flush code for the view is [here](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L6503), and it delegates to individual flush functions [here](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L6466).<br>
  * In most cases, flushing to the db just requires first [deleting entries that have i`sDeleted=true`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L6347) and then [writing entries that have isDeleted=false](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L6384).<br>
  * The core ProcessBlock function basically just applies all the txns in a block to a view via [`ConnectBlock()`](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L1688) and then [flushes it](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L1725). The mempool uses a view to validate transactions as well [inside of its core `processTransaction` function](https://github.com/deso-protocol/core/blob/135c03a/lib/mempool.go#L1402).<br>
* We can walk through connecting an UpdateProfile transaction to see how it works.<br>
  * `_connectTransaction` delegates to [`_connectUpdateProfile`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L5069)\`\`<br>
  * [A bunch of validation happens](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L4069)<br>
  * UTXO's are generally always checked by a call to [`_connectBasicTransfer`](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L4129), which returns the total input and output of the transaction.<br>
  * An existing profile entry is [looked up](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L4108) if one exists. If it exists, it is updated. Otherwise, a new one is created from scratch.
    * Updating an existing profile happens [here](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L4154) while creating a new one happens [here](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L4195).<br>
  * In both cases, mappings for the profile are first [deleted from the view](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L4242) and then [set on the view](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L4246).<br>
    * Note that deleting something from the view never actually deletes a mapping, it only marks it as `isDeleted=true`.\
      \
      This is because the flush needs to propagate this change to the db, and it can only do that if it knows the entry is scheduled to be deleted by leaving it in the view.<br>
  * Finally, [some information is saved](https://github.com/deso-protocol/core/blob/135c03a/lib/block_view.go#L4249) that allows us to roll back or "disconnect" the transaction in the future if needed.<br>
* Every transaction has both a `_connect` and a `_disconnect`.\
  \
  The `_disconnect` restores the view to the state it was in before the transaction was connected. `_disconnect` code is rarely used, but it supports reorgs of blocks, which happen from time to time.<br>
  * During a reorg, we need to disconnect some transactions from some blocks and connect transactions from some other blocks in order to validate the fork, \*before\* writing anything to the db. \
    \
    This happens in [ProcessBlock here](https://github.com/deso-protocol/core/blob/135c03a/lib/blockchain.go#L1786).


# Setup a Node & Frontend Locally

This doc will teach you how to set up your dev environment.\
\
Although it's not a hard prerequisite, we recommend skimming the [DeSo Code Walkthrough](broken://pages/-MjtsPMOOgo2oTbs7XKU) first, as it provides some useful context.

## Prerequisites

To run the frontend repo, you will need to be running **Node v13.13.0** and **NPM 6.14.4.**\
\
We recommend using NVM to set this environment up. To run the backend you'll need Go v1.15.6 installed.\
\
These can be installed via [homebrew](https://brew.sh/) by running:

```bash
brew install nvm
# follow the output to set up your ~/.nvm folder, nvm script, and shell completion
nvm install 13
# check the versions
node -v
npm -v
# then install go
brew install go@1.15
# check the version
go version
```

\
We will also assume that you have [Goland](https://www.jetbrains.com/go/) installed. This is the recommended IDE for developing on DeSo since most of the code is Go code.<br>

Another prerequisite is [vips](https://github.com/libvips/libvips) which can be installed with [homebrew](https://brew.sh/) – `brew install vips` – or `apt install libvips-tools` on Ubuntu.<br>

## Setup

First, you must checkout all repos into the same directory.\
\
Some of these repos are technically optional, but checking them all out allows you to hop around the code more easily.

```
cd $WORKING_DIRECTORY
git clone https://github.com/deso-protocol/core.git
git clone https://github.com/deso-protocol/backend.git
git clone https://github.com/deso-protocol/frontend.git
git clone https://github.com/deso-protocol/identity.git
```

Once all of these repos are checked out, we recommend importing them into a single Goland project. This allows you search across and develop on all of of the repos concurrently.\
\
To do this, open **Goland, hit File > Open**, select a repo folder, and select "**Attach**" when prompted.\
\
If you do this correctly, you should have all four repos loaded into a single Goland project.

If you're not familiar with Goland, the following hotkeys are useful for jumping around the code ([full cheat sheet here](https://www.jetbrains.com/help/go/mastering-keyboard-shortcuts.html)):

* **SHIFT+SHIFT:** Open any file across all four repos with fuzzy search.
* **CTRL+SHIFT+F:** Search across all four repos at once with regexes.
* **CTRL+SHIFT+A:** Runs any action that you would normally find in a menu.
* **CTRL+B:** Jump to definition or find usages.

If you like Vim, you can also install the Vim plugin so you get your typical Vim hotkeys.<br>

## Building and running locally

### Running the frontend in development mode

```
# Assume we're starting in $WORKING_DIRECTORY, which contains all the repos
cd frontend
npm install

# The following command will serve the frontend on localhost:4200 with
# auto-reloading on changes. You must run a node before the site will
# actually work however (see next section).
npm start
```

### Running the node in testnet mode

```
# Assume we're starting in $WORKING_DIRECTORY, which contains all the
# repos. Also assume we have "ng serve" running.
cd backend/scripts/nodes

# The n0_test script runs a testnet blockchain locally. It starts mining 
# blocks immediately at a much faster rate than mainnet. You can set your 
# public key to receive the block rewards by setting it as --miner-public-key 
# in the arguments. This gives you funds that you can test with. You can see 
# the status of the node by going to the Admin tab after logging in with an
# account and then going to the Network subtab.
export CGO_CFLAGS_ALLOW="-Xpreprocessor"
./n0_test

# Once n0_test is running, you must navigate to the following URL. 4200 is the
# port for ng serve. Note that in order to be 
http://localhost:4200
```

\
By default, your browser will point at `localhost:17001`, which is the default "mainnet" API port. \
\
However, when you run n0\_test, your node spins up on `localhost:18001`.\
\
To point your frontend at your testnet node, however, you must open up your inspector and change your `lastLocalNodev2` parameter to `localhost:18001` as shown in the screenshot below.\
\
After you do this, you should be able to Sign Up, and everything should work normally.<br>

![](/files/O0V367PnynenDFlN7dFf)

### Running the node in mainnet mode

Most of the time, we develop using testnet mode because it's fast and cheap.\
\
However, to make sure our changes work before pushing we like to run full-blown mainnet nodes locally.

```
# Assume we're starting in $WORKING_DIRECTORY, which contains all the repos.
# Also assume we have "ng serve" running.
cd backend/scripts/nodes

# The n0 script runs a node that connects to mainnet peers. It will download
# all the blocks from its peers and then start syncing its mempool from them.
# You can see the status of the node by going to the Admin tab after
# logging in with an account and then going to the Network subtab. Note that
# syncing the blockchain may take an hour or so.
$ ./n0

# Once n0 is running, you must navigate to the following URL. 4200 is the
# ng serve port. It should automatically hit your node, which should be
# exposing its API at localhost:17001.
http://localhost:4200
```

## Running a local identity service (optional)

Running an identity service locally is generally not required.\
\
However, doing so is as easy as running the Angular app:

```
# Assume we're starting in $WORKING_DIRECTORY, which contains all the repos
cd identity
npm install

# Install angular cli
sudo npm install -g @angular/cli typescript tslint dep

# The following command will serve identity on localhost:4201 with
# auto-reloading on changes.
ng serve --port 4201
```

In order to point your browser at your local identity service rather than at identity.deso.org, you must change a localStorage value similar to what we did to get the testnet node running.\
\
In this case, we must change `lastIdentityServiceURL` to `http://localhost:4201`.\
\
See the screenshot below:

![](/files/P5SQFQTvpnDCD34Q6377)


# Making Your First Changes

In this tutorial, we will show you how to make changes to the DeSo codebase, and see your changes reflected in a local dev environment.

## Prerequisites

This guide assumes you have successfully made it through [**Setting Up Your Dev Environment**](broken://pages/-MjtsPMMcHzdqdJ1owgy).\
\
In particular, it assumes you have a testnet node running with n0\_test showing a frontend UI that looks roughly like the following screenshot:

![](/files/W4nELE5otnah6oXsiiUS)

## Make Your First Frontend Change

If your frontend repo is loaded into Goland, the following steps should allow you to make your first frontend change, and see it update your local node in real time:<br>

* Run your n0\_test. Create an account and make sure you can see the page shown in the prerequisites.<br>
* Assuming you're using Goland, navigate to the `feed.component.ts`. Hint: You can use SHIFT+SHIFT to easily jump to it.<br>
* Look for the `GLOBAL_TAB` function in the file and modify the return statement as follows (you can name your feed whatever you want):<br>
  * `static GLOBAL_TAB = "Satoshi's Feed";`<br>
* Save your changes.

\
After your changes are saved, your browser should update to show a new title for your feed tab:

![](/files/zdfonpjptjw2hmAFer2E)

## Make Your First Backend Change

The backend repo runs an API that the frontend Angular app queries to get all of the information it displays. Let's make our first change to this API by following the steps below:<br>

* Before going into the code, go to the Admin panel, add a post to the global feed, and verify that it shows up by refreshing the page.<br>

* With the backend repo loaded in Goland, find the `post.go` file, which defines one of the API endpoints queried by the frontend. Hint: You can use SHIFT+SHIFT to navigate to it.<br>

* In that file, find a function called `GetPostsStateless`. Modify the response at the end of the function as follows to customize the content:<br>
  * ```
        if len(postEntryResponses) > 0 {
            postEntryResponses[0].Body = "This is some content"
        }

        // Return the posts found.
        res := &GetPostsStatelessResponse{
            PostsFound: postEntryResponses,
        }
    ```

* Save the file and restart n0\_test. When you make changes to anything in backend or core, you need to restart your node for them to take effect.<br>

Now you should see some custom content in the post that you added to the feed. You can modify endpoints in backend like this one to customize how data is returned to the user.

![](/files/E91cbcStOlnknnauhGEh)

##


# DeSo Roadmap

## Phase 3: Revolution

<table><thead><tr><th width="120">Date</th><th>Release</th></tr></thead><tbody><tr><td>Q1 2024</td><td><strong>Focus Reservation Period </strong><mark style="color:green;"><strong>(Launched)</strong></mark><br><br>Focus (focus.xyz) launches publicly for reservations.<br><br><a href="https://diamondapp.com/u/nader/blog/announcing-focus-white-paper-and-tokenomics">https://diamondapp.com/u/nader/blog/announcing-focus-white-paper-and-tokenomics</a><br></td></tr><tr><td>Q2 2024</td><td><p><strong>Automated Market-Makers launch on the DeSo DEX. </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><p>The DeSo DEX is the first fully on-chain order-book DEX, supporting the cross-chain trading of BTC, ETH, SOL, USDC, and DESO via the Openfund client. The DeSo DEX has allowed us to develop the first order-book AMMs, which have been in development for over a year, and which will power Focus Tokens (one-click Meme Coins and Creator Coins). As a trial run, we will be launching our AMMs on the DeSo DEX for the BTC, ETH, SOL, DESO, and OPENFUND markets.</p><p>This will vastly increase liquidity for these pairs, allowing anyone to buy and sell hundreds of thousands in cross-chain assets fully on-chain with minimal price impact.<br></p></td></tr><tr><td>Q2-Q4 2024</td><td><p><strong>- Revolution PoS launches on testnet. </strong><mark style="color:green;"><strong>(Launched)</strong></mark><br><br>This is the biggest upgrade to the DeSo blockchain ever, years in the making, and arguably the most advanced consensus of any blockchain. Revolution will bring with it:</p><p><strong>• 20% initial APY</strong> for staking DESO<br></p><p><strong>• 1 second</strong> confirmation times<br></p><p><strong>• 500 posts per second</strong>, and even higher “transactions” per second. This is ~1/10th of Twitter-scale. Anyone who said a blockchain can’t power a Twitter-scale application will be proven wrong.<br></p><p><strong>• Liquid bonding.</strong> Stake and unstake with minimal cooldown time (2 hours on Revolution vs weeks on other top-tier layer-1 chains)<br></p><p><strong>• No slashing.</strong> Revolution maintains security without slashing, allowing you to stake confidently without risk to your principal.<br></p><p><strong>• Auto-compounding.</strong> Staking rewards can be automatically restaked without having to manually claim rewards.<br></p><p><strong>• Burn-Maximizing Fee Mechanism.</strong> Revolution burns the theoretical maximum amount per transaction thanks to its “BMF” mechanism, maximizing deflation for coin-holders.<br></p><p><strong>• Fully permissionless and decentralized.</strong> Revolution PoS maximizes decentralization, scaling to tens of thousands of nodes, ensuring no single entity can unilaterally control the network or censor users. Anyone can join the network and be a validator with a minimal amount of stake.<br></p><p><strong>• Low-cost and simple.</strong> Revolution PoS is a simple protocol, and anyone can run a node on commodity hardware.<br></p><p><strong>- May/June: Revolution PoS launches on mainnet. </strong><mark style="color:green;"><strong>(Launched)</strong></mark><br><br>After two to four weeks of stable block production on testnet, Revolution will be ready for prime-time and the mainnet fork will trigger.<br></p></td></tr><tr><td>Q1 2025</td><td><strong>Openfund V2 Launches</strong><br><a href="https://docs.deso.org/openfund/what-is-openfund">See Openfund Docs</a></td></tr><tr><td>Q1 2025</td><td><p><strong>Focus ($FOCUS) launches on HeroSwap &#x26; Openfund</strong><br><br>Focus brings with it a long list of pioneering crypto innovations. For the full list and details, check out our white paper on focus.xyz. We are fairly confident in the June/July timing at this point. We are cutting no corners, and we think it will be worth the wait!<br></p><p><strong>• Join to Earn.</strong> The first component of Focus’s viral engine.<br></p><p><strong>• Refer to Earn.</strong> The second component of Focus’s viral engine.<br></p><p><strong>• The Bounty Hunter.</strong> The third component of Focus’s viral engine.<br></p><p><strong>• Focus Tokens.</strong> One-click Meme Coins and Creator Coins using our state-of-the-art on-chain order-book AMMs. Focus Tokens will also support <strong>on-chain vesting schedules and fully-customizable on-chain yield curves</strong>. Focus Tokens will mint on Focus and trade on the DeSo DEX via the Openfund client.<br></p><p><strong>• On-chain Subscriptions</strong> (with crypto-native payment)<br></p><p><strong>• On-chain Paid Unlockable Content</strong> (with crypto-native payment)<br></p><p><strong>• On-chain Encrypted Paid Messages</strong> (with crypto-native payment)<br></p><p><strong>• On-chain Peer to Peer Content Tipping</strong> (with crypto-native payment)<br></p><p><strong>• Decentralized Advertising</strong> (with crypto-native payment)<br><br><strong>• Custom Feeds &#x26; Feed Marketplace.</strong> Focus will allow you to adjust all of the parameters that go into computing your feed, creating the first customizable feed experience. Only possible thanks to DeSo’s fully on-chain content.<br></p></td></tr><tr><td>Q3 2025</td><td><p><strong>The Decentralized Web and DeSo Drive</strong></p><ul><li>Today, DeSo supports storage of social content: profiles, posts, follows etc… But soon we will be upgrading DeSo to support encrypted and unencrypted raw file storage.</li><li>Users will be able to use DeSo Drive to store content directly onto the DeSo blockchain, allowing DeSo to take over the role Amazon’s s3 plays on the internet today</li><li>DeSo will also support rendering of static html pages uploaded to a DeSo Vault, making DeSo a new foundation for hosting a fully-decentralized internet. We call this The Decentralized Web.</li></ul></td></tr></tbody></table>

## Phase 2: The Internet of DeSo

<table><thead><tr><th width="121.33333333333331">Date</th><th width="612">Release</th></tr></thead><tbody><tr><td><strong>Q4 2022</strong><br><br><br><br><br><br><br><br><br><br><br><br><br></td><td><p><strong>Long-Form Content Standard </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>Today, people post long-form content to Medium, a centralized platform, or their own self-hosted blogs, which give them no distribution.</li><li>DeSo can combine the distribution of a platform like Medium or Twitter with the control and censorship resistance that comes from self-hosted blogs. And, of course, provide many untapped ways to monetize, like diamonds, NFTs, creator coins, and much more.</li><li>After DeSo standardizes long-form, we think we can make it the #1 destination to share long-form thoughts.<br><br><a href="https://diamondapp.com/u/nader/blog/decentralizing-writing-creating-an-internet-of-ideas">https://diamondapp.com/u/nader/blog/decentralizing-writing-creating-an-internet-of-ideas</a></li></ul></td></tr><tr><td><p><strong>Q1 2023</strong></p><p><br></p><p><br></p></td><td><p><strong>On-Chain Group Chats with End-to-End Encryption </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>DeSo is already the only blockchain in the world that can support on-chain fully censorship-resistant end-to-end encrypted DMs with on-chain social graphs and identity — and we are extending that functionality to group chats!</li><li>Users will be able to create fully end-to-end encrypted censorship-resistant on-chain groups and add + remove other users from them.</li><li>Similar to secure on-chain DMs, this will be an even more impressive “first of its kind” for DeSo.</li><li>We're calling this <strong>"The DeSo Chat Protocol"</strong><br><br><a href="https://diamondapp.com/u/deso/blog/the-social-network-hard-fork?feedTab=Following">https://diamondapp.com/u/deso/blog/the-social-network-hard-fork</a></li></ul></td></tr><tr><td><strong>Q1 2023</strong><br><br><br><br><br><br><br><br><br><br><br><br><br></td><td><p><strong>On-Chain Private Content with End-to-End Encryption </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>Today, DeSo offers great “public square” functionality. Your posts are broadcasted publicly on-chain for everyone to see but people want to be able to make posts on-chain that only their followers can see.</li><li>DeSo will be launching an end-to-end encrypted on-chain solution for this, leveraging the innovations behind on-chain end-to-end encrypted group chats.</li><li>This functionality will enable new forms of censorship-resistant communication with followers, as well as new forms of monetization, like subscription models employed by apps like Patreon<br><br><a href="https://diamondapp.com/u/deso/blog/the-social-network-hard-fork?feedTab=Following">https://diamondapp.com/u/deso/blog/the-social-network-hard-fork</a></li></ul></td></tr><tr><td><strong>Q1 2023</strong><br><br><br><br><br><br><br><br><br><br><br><br><br></td><td><p><strong>Associations </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>DeSo will launch a new on-chain primitive called “associations,” which will allow users and app developers to create relationships between users and between users’ content.</li><li>This new primitive will be used to implement <strong>decentralized verifications</strong>, as well as on-chain “reactions” and on-chain “blocks” of other users’ content.</li><li>Associations introduce a decentralized form of authority, effectively implementing previous “web of trust” proposals from the early internet and academia.<br><br><a href="https://diamondapp.com/u/deso/blog/the-social-network-hard-fork?feedTab=Following">https://diamondapp.com/u/deso/blog/the-social-network-hard-fork</a></li></ul></td></tr><tr><td><p><strong>Q1 2023</strong></p><p><br></p><p><br><br><br><br></p></td><td><p><strong>Listing Blitz </strong><mark style="color:green;"><strong>(Continued Progress)</strong></mark></p><ul><li>We will build a pipeline of exchanges and work with them all to list DeSo</li><li>This, combined with an increased focus on recruiting credible market-makers, should significantly increase global $DESO liquidity</li><li><p>New Listings:</p><ul><li>Gate.io (<a href="https://diamondapp.com/posts/e4e48726ca1d63423feebcc9077459637506e33684279461ef981d004f5af91c">announcement</a>)</li><li>BitMart (<a href="https://diamondapp.com/posts/1d03431d05f260b72fe73b8960ea949adb9c0a68301f7b835ac6daaf8473b935">announcement</a>)</li><li>LBank (<a href="https://twitter.com/desoprotocol/status/1661409001530331136">announcement</a>)</li></ul></li></ul></td></tr><tr><td><strong>Q1 2023</strong><br><br><br><br><br><br><br></td><td><p><strong>DeSo Social Wallet v1 </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>A brand new self-custodial DeSo Social Wallet that offers a central place to see all of your social assets including NFTs, DeSo Tokens, Creator Coins, and Social Graph with one-of-a-kind features like NFT PFPs and Derived Key Management.<br><br><a href="https://signup.deso.com/wallet">https://signup.deso.com/wallet</a></li></ul></td></tr><tr><td><p><strong>Q1 2023</strong><br></p><p><br><br><br><br></p></td><td><p><strong>Princeton x DeSo </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>The Princeton x DeSo Startup Competition is a four-week hackathon-style event made for students looking to create and launch the Next Big Thing (using Openfund).<br><br><a href="https://www.deso.com/princeton/">https://www.deso.com/princeton/</a></li></ul></td></tr></tbody></table>

## Phase 1: The Social Layer of Web3

Phase one aims to solidify DeSo as a cross-chain “social layer” for all of web3, starting with a first-of-its-kind social integration with MetaMask and Ethereum Addresses.

<table><thead><tr><th width="121.33333333333331">Date</th><th width="612">Release</th></tr></thead><tbody><tr><td><strong>Q3 2022</strong><br><br><br><br><br><br><br><br><br><br><br><br><br><br></td><td><p><strong>MetaMask Integration </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>This launch will mark a transition from DeSo being a single-chain ecosystem to becoming a cross-chain “social layer” for all blockchains, including Ethereum, Solana, and many others</li><li>This launch can enable integrations with ETH-focused platforms. For example, NFT marketplaces like Rarible, Foundation, or OpenSea which have millions of MetaMask users in need of a decentralized social layer for comments, DMs, group chats, and much more.</li><li>With this launch, millions of MetaMask accounts will also gain access to the DeSo ecosystem<br><br><a href="https://diamondapp.com/posts/f3f6343eb166e93036d6bd80ad1e20939973ad0c53449243451df76bf835cab1">https://diamondapp.com/posts/f3f6343eb166e93036d6bd80ad1e20939973ad0c53449243451df76bf835cab1</a></li></ul></td></tr><tr><td><strong>Q4 2022</strong><br><br><br><br><br><br><br><br><br><br></td><td><p><strong>Flux Integration </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>DeSo applications can now integrate seamlessly with their decentralized cloud infrastructure, and all that's needed is a basic docker image of your project.</li><li>You can instantly start to develop, manage, and spawn your applications on multiple servers at once.<br><br><a href="https://diamondapp.com/posts/dd4ba4d6683383c9cb1e40c84c6314cf6edc49273235ca7e30adbd879b588a9d">https://diamondapp.com/posts/dd4ba4d6683383c9cb1e40c84c6314cf6edc49273235ca7e30adbd879b588a9d</a></li></ul></td></tr><tr><td><p><strong>Q4 2022</strong></p><p><br><br><br><br><br><br></p></td><td><p><strong>DesoDollar </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>We are launching a breakthrough stablecoin that will enable low-fee USD transactions on DeSo</li><li>DesoDollar will be fully backed, fully exchange-able and interoperable with USDC<br><br><a href="https://diamondapp.com/posts/c58ad7e2c9046f0baf0c7448c252f68fdd682a78da486982ad2a795b0455df82">https://diamondapp.com/posts/c58ad7e2c9046f0baf0c7448c252f68fdd682a78da486982ad2a795b0455df82</a></li></ul></td></tr><tr><td><p><strong>Q4 2022</strong></p><p><br><br><br><br><br><br><br><br><br></p></td><td><p><strong>HeroSwap Early-Beta </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>We have been working on a platform we think of as the “Stripe for Crypto.” We have been beta-testing it on Openfund and Diamond, but soon it will launch publicly</li><li>The HeroSwap platform will allow for the cross-chain exchange of any cryptocurrency for another via simple API</li><li>There is no other platform that allows blockchains to interoperate this way. HeroSwap will be a global “money router” between all blockchains<br><br><a href="https://diamondapp.com/posts/84fdd166fc3ae09a8569beaa8f8a03239c2ce747740d1b3cb05cb675ef5a1385">https://diamondapp.com/posts/84fdd166fc3ae09a8569beaa8f8a03239c2ce747740d1b3cb05cb675ef5a1385</a></li></ul></td></tr><tr><td><strong>Q4 2022</strong><br><br><br><br><br><br><br><br><br><br><br><br><br></td><td><p><strong>USD Treasury on Openfund </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>The #1 request from top fundraisers when evaluating Openfund is to be able to raise with a USD treasury, which is now possible thanks to DesoDollar and Megaswap.</li><li>Openfund will support the ability to accept funds in *any* cryptocurrency (currently ETH, BTC, SOL, DESO, and USDC), and auto-convert to USD via DesoDollar.</li><li>Projects can raise from communities across many different blockchains, and then cash out their funds to USDC to achieve their goals.<br><br><a href="https://diamondapp.com/posts/ec8fb4d9e6ad07716c13e0c8c6e63fd8d3167604ead4ae98e1c5d78bcde41fcc">https://diamondapp.com/posts/ec8fb4d9e6ad07716c13e0c8c6e63fd8d3167604ead4ae98e1c5d78bcde41fcc</a></li></ul></td></tr><tr><td><strong>Q4 2022</strong><br><br><br><br><br><br><br><br><br><br></td><td><p><strong>New COO Joins </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>DeSo has historically under-invested in business development and marketing, and we are hiring a key partner to fix that</li><li>Our COO will start by re-engaging all major DESO holders, building a pipeline of potential partners, and building a pipeline of new potential DESO investors<br><br><a href="https://diamondapp.com/posts/4b79b09c6683ec13024888fba97bd4a2d6ff15ba58a3d0d178ef74f8c188a5b8">https://diamondapp.com/posts/4b79b09c6683ec13024888fba97bd4a2d6ff15ba58a3d0d178ef74f8c188a5b8</a></li></ul></td></tr></tbody></table>

## Phase 0: From Beginning to Present

<table><thead><tr><th width="121.33333333333331">Date</th><th width="612">Release</th></tr></thead><tbody><tr><td><strong>Q2 2019</strong><br><br><br><br></td><td><p><strong>Early Research &#x26; Development Begins </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>Nader Al-Naji begins exploring decentralized social use cases and learns that existing blockchains like Ethereum weren't equipped to handle the storage and indexing requirements of social media at scale</li></ul></td></tr><tr><td><strong>Q1 2021</strong><br><br><br><br><br><br><br><br><br><br><br><br><br><br></td><td><p><strong>Decentralized Twitter Prototype (BitClout) on</strong> <strong>DeSo </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li><p>Support for full Twitter functionality on-chain</p><ul><li>Profiles, Posts, Follows, Likes, etc…</li><li>End-to-end encrypted DMs on-chain (unprecedented)</li></ul></li><li>Creator Coins took the world by storm as the first asset class that enabled investing in reputation</li><li>Supported ~100k simultaneous DAUs, showing that the DeSo infrastructure can support decentralized social apps at scale</li><li>Fully open-sourced frontend and backend<br><br><a href="https://diamondapp.com/nft/75f16239b57de0531f9579f3817beb0a67515e4999947f293c112fb0260178e4">https://diamondapp.com/nft/75f16239b57de0531f9579f3817beb0a67515e4999947f293c112fb0260178e4</a></li></ul></td></tr><tr><td><strong>Q2 2021</strong><br><br><br></td><td><p><strong>First Listing on Blockchain.com </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>DeSo’s first exchange listing via blockchain.com<br><br><a href="https://diamondapp.com/posts/f9249d4e7b14d4b7ab3b9fd3798db659c3a8c2aeedc6f76e2019b122d090576a">https://diamondapp.com/posts/f9249d4e7b14d4b7ab3b9fd3798db659c3a8c2aeedc6f76e2019b122d090576a</a></li></ul></td></tr><tr><td><p><strong>Q2 2021</strong></p><p><br><br><br><br></p></td><td><p><strong>Social Tipping aka "Diamonds" </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>DeSo pioneers micro-tipping transactions using cryptocurrency in a social app<br><br><a href="https://diamondapp.com/posts/21f9c1e3e570ad2ab8f509bd95ef50d13a05f6c53d752028ac90ea0afa1e10f6">https://diamondapp.com/posts/21f9c1e3e570ad2ab8f509bd95ef50d13a05f6c53d752028ac90ea0afa1e10f6</a></li></ul></td></tr><tr><td><strong>Q3 2021</strong><br><br><br><br><br><br></td><td><p><strong>NFTs on DeSo </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>DeSo supports the full ERC-721 standard and becomes the first blockchain to support fully on-chain NFT auctions<br><br><a href="https://diamondapp.com/nft/89561b924ab9d51ea16320a55fe7224b40d6b85d5e73b25297de9a67452acc78">https://diamondapp.com/nft/89561b924ab9d51ea16320a55fe7224b40d6b85d5e73b25297de9a67452acc78</a></li></ul></td></tr><tr><td><strong>Q3 2021</strong><br><br><br></td><td><p><strong>DeSo Blockchain Public Launch </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>DeSo Foundation is established to advance the development of the core protocol and ecosystem<br><br><a href="https://diamondapp.com/posts/89d2d0d02e1b41254992e1c09d9dd4973ce6b8d33fa33edfbb08d67acc4afc53">https://diamondapp.com/posts/89d2d0d02e1b41254992e1c09d9dd4973ce6b8d33fa33edfbb08d67acc4afc53</a></li></ul></td></tr><tr><td><strong>Q4 2021</strong><br><br><br><br><br></td><td><p><strong>Derived Keys &#x26; Spending Limits </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>DeSo becomes the first blockchain capable of supporting subscription models and secure offline transactions<br><br><a href="https://github.com/deso-protocol/core/releases/tag/v1.1.6">https://github.com/deso-protocol/core/releases/tag/v1.1.6</a></li></ul></td></tr><tr><td><strong>Q4 2021</strong><br><br><br></td><td><p><strong>DESO is Listed on Coinbase </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>$DESO becomes one of the fastest layer-1 blockchains ever to list on Coinbase<br><br><a href="https://www.coinbase.com/blog/decentralized-social-deso-is-launching-on-coinbase-pro">https://www.coinbase.com/blog/decentralized-social-deso-is-launching-on-coinbase-pro</a></li></ul></td></tr><tr><td><strong>Q1 2022</strong><br><br><br><br><br></td><td><p><strong>The Social ERC20 Standard on DeSo </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>Allows for low-fee ERC20 minting, burning, and indexing via a social profile.<br><br><a href="https://github.com/deso-protocol/dips/blob/main/dips/dip-6.md">https://github.com/deso-protocol/dips/blob/main/dips/dip-6.md</a></li></ul></td></tr><tr><td><p><strong>Q1 2022</strong><br></p><p><br><br></p></td><td><p><strong>Hypersync Launches </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>Bleeding-edge technical innovation that lowered sync time from 12 hours to 10 minutes<br><br><a href="https://blog.deso.com/blog/hypersync-faq">https://blog.deso.com/blog/hypersync-faq</a></li></ul></td></tr><tr><td><p><strong>Q1 2022</strong><br><br></p><p><br></p></td><td><p><strong>DeSo Javascript Framework </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>Deso.js, a Javascript framework for interacting with the DeSo blockchain via its web2 API endpoints launches<br><br><a href="https://github.com/deso-protocol/deso-workspace/tree/master/libs/identity">https://github.com/deso-protocol/deso-workspace/tree/master/libs/identity</a></li></ul></td></tr><tr><td><p><strong>Q2 2022</strong><br></p><p><br><br><br></p></td><td><p><strong>DeSo DEX Orderbook </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>First-of-its-kind fully <strong>on-chain</strong> <strong>non-custodial order-book</strong> exchange, capable of supporting up to 40k matches per second.<br><br><a href="https://openfund.com/trade">https://openfund.com/trade</a></li></ul></td></tr><tr><td><p><strong>Q2 2022</strong><br><br><br><br><br><br><br><br><br></p><p><br><br><br><br><br><br></p></td><td><p><strong>Openfund Beta Launches (Formerly DAODAO) </strong><mark style="color:green;"><strong>(Launched)</strong></mark></p><ul><li>Building a developer ecosystem starts with an efficient way for developers who are working on interesting projects to get funding.<br><br>Openfund created a decentralized mechanism for developers to raise money from not just the DeSo community, but also the broader web3 community thanks to its clever use of cross-chain swaps via MegaSwap.<br></li><li>Openfund was also the first real-world application to leverage Social ERC20s, cross-chain currency swaps, and on-chain order matching, serving as an example for the web3 ecosystem.<br><br><a href="https://www.globenewswire.com/en/news-release/2023/01/10/2586280/0/en/Coinbase-Backed-Openfund-Pioneers-New-Fundraising-Model-Powered-by-Decentralized-Social.html">https://www.globenewswire.com/en/news-release/2023/01/10/2586280/0/en/Coinbase-Backed-Openfund-Pioneers-New-Fundraising-Model-Powered-by-Decentralized-Social.html</a></li></ul></td></tr></tbody></table>


# DeSo Tech Stack

An overview of tools & resources for building on DeSo

{% embed url="<https://www.youtube.com/watch?v=q2FPbh6zBTg>" %}
Learn about the advantages of building on DeSo in 90 seconds
{% endembed %}

\
The DeSo Foundation's goal is to give founders and developers a set of world-class tools and resources to focus on building decentralized social and consumer-focused applications.

There will be countless other ideas and opportunities that arise as DeSo unlocks an army of web2 developers who are aching to participate in the future of decentralization and social.&#x20;

## Building on DeSo

We make it incredibly simple and easy for anyone, even with little knowledge about blockchains and web3, to get started building decentralized apps that can target mainstream audiences.

We strive on the following development principles:

### **1) Easy for web2 developers to build.**

* **API-Driven & Permissionless**\
  Everything that DeSo builds is API-driven from the start. We believe this makes it easier for Web2 developers to focus on creating world-class Web3 applications, using familiar programming languages like [Javascript](/deso-frontend/exchange-listing-api) & Python. There's no need to learn smart-contract languages and write cost-prohibitive contracts.\
  \
  Anyone in the world can also run their own DeSo node to curate and moderate their own feed. Read more: [Feeds & Moderation](/deso-features/feeds-and-moderation)<br>
* **Virtually Zero Gas Fees**\
  On DeSo, you'll never expect to pay more than a fraction of a penny for thousands of on-chain transactions. The average fee per post is <$0.000017, in contrast to Ethereum where the average fee per post can cost >$50 depending on gas fees.\
  \
  DeSo solves very complex storage & indexing problems to be able to handle decentralized social applications extremely efficiently. This is an advantage of DeSo being an "infinite-state" blockchain that's optimized for storage-heavy use cases. Read more: [Infinite-State](/deso-blockchain/infinite-state)<br>
* **Solving the Cold-Start Problem**\
  DeSo solves cold-start problems for developers in **three** very significant ways:<br>
  * **User & Content Liquidity.** Developers can tap into an open firehose of millions of wallets, profiles, and content from day one of launching your application.<br>
  * **Blockchain-Level Features.** Developers are provided with on-chain money & social features out-of-the-box, without needing to write a single line of smart-contract logic. Every new feature added benefits all apps being built on the blockchain.\
    \
    This creates unprecedented speed and parallelization for social applications to build world-class products with far fewer off-chain centralization risks.<br>
  * **Cross-Chain Social Layer.** Developers can utilize built-in support for cross-chain onboarding with features like "Sign in With MetaMask" & swapping between ETH and DESO via [MegaSwap](https://megaswap.xyz/).\
    \
    Support for additional Layer-1s like Solana, NEAR, Cardano, Avalanche, Polygon, and more will be planned. This will also open up cross-chain wallet-2-wallet messaging to build a truly universal social layer of Web3.

### **2) Easy for mainstream users to onboard.**

* **Frictionless Usage & Onboarding**\
  DeSo is a very user-experienced-driven project, as we believe the key to Web3 social is to make the user experience on par with the expectations of Web2 social.\
  \
  This means unlike other blockchains, DeSo makes it very simple to sign up and try applications with an identity, wallet, and free "starter $DESO" to start engaging.\
  \
  Users also don't have to worry about exorbitant gas fees or explicitly approving each transaction when engaging on DeSo. We always continue to aim to remove friction wherever necessary.\
  \
  Here's a list of how DeSo Identity solves many of these problems:<br>
  * **Sign in with DeSo**
    * Any developer can add a "Sign in With DeSo" login with a [few lines of Javascript](/deso-frontend/exchange-listing-api).<br>
  * **Self-Custodial Wallet**
    * Take full custody of your own keys. We like to say "***not your keys, not your content***". <br>
  * **Multiple Login Options**
    * For Ethereum Users: "Sign in with MetaMask"
    * For Mainstream Users: "Sign in with Google"
    * For Any User: "Sign in with DeSo Seed" (advanced)<br>
  * **Starter $DESO**
    * All users can attain a small amount of starter DESO for free (which will potentially last forever) by verifying their phone number.<br>
  * **Social Graph & Content**
    * Take your content, followers, identity, and social graph with you anywhere. You take full ownership of the data you generate.<br>
  * **Store Your Assets**
    * All of your NFTs, Creator Coins, and DeSo Tokens are coupled with your Identity. See an example here: <https://signup.deso.com/wallet><br>
* **Privacy & Safety**\
  DeSo was built with ideas like Account Abstraction in mind from day one. \
  \
  We utilize "derived keys" and "spending limits" which makes it safer to give permissions to specific applications like posting, commenting, or following — without giving up your private keys.\
  \
  We are firm believers that user primary keys should **never** be shared with third-party applications, regardless of their security practices, and so we created derived keys, which significantly lower attack vectors related to unauthorized access to user credentials.\
  \
  Derived keys are impermanent and they usually automatically expire about 30 days after being issued and can also be de-authorized at any point.

### **3) Easy for creators to engage & monetize.**

* **Monetization & Social Features**\
  A unique advantage for DeSo being its own layer-1 is that the blockchain combines social + money transactions very seamlessly.\
  \
  This allows DeSo offers multiple methods of on-chain monetization and social features for developers to build on, like the following:<br>
  * **Social Graph & Identity**
    * On-chain social identity
    * On-chain social graph
    * On-chain user associations (verifications, blocks, etc)
    * On-chain profile metadata <br>
  * **Social Actions**
    * On-chain follows
    * On-chain likes
    * On-chain replies, comments & threads
    * On-chain reposts & quote posts
    * On-chain post associations (moderation, reactions, polls, etc.)
    * On-chain post metadata <br>
  * **Social Tipping**
    * On-chain basic transfers <br>
  * **Social Tokens (Creator Coins)**
    * On-chain creator coin transfers
    * On-chain founders rewards<br>
  * **Social NFTs**
    * On-chain creator royalties
    * On-chain coin-holder (community) royalties
    * On-chain bids & auctions
    * On-chain royalty splits
    * On-chain exclusive content
    * On-chain NFT transfers
    * On-chain NFT burns<br>
  * **DeSo Tokens (Formerly DAO Coins)**
    * On-chain minting & burning
    * On-chain limit orders
    * On-chain token transfers<br>
  * **E2E Encrypted Messaging**
    * On-chain end-to-end encrypted direct messaging (DMs)
    * On-chain end-to-end encrypted group chat messaging<br>
  * **E2E Encrypted Content (Access Groups)**
    * On-chain end-to-end encrypted content<br>
  * **Social Stable Coins**
    * On-chain stable coins (DesoDollar)<br>
  * **File Storage (coming soon with DeSo Vaults)**
    * On-chain blob storage for images & videos (soon)
    * On-chain file storage for static HTML websites (soon)


# DeSo Applications

An overview of ideas and applications in the DeSo ecosystem.

{% hint style="info" %}
**Are you building on DeSo?** Submit your app by [messaging @deso](https://diamondapp.com/u/deso) on-chain.\
**Are you fundraising on DeSo?** We recommend [Openfund](https://openfund.com) for easy web3 fundraising!
{% endhint %}

{% embed url="<https://www.youtube.com/watch?v=3XunCyyxt7A>" %}
With DeSo, you can create one profile, and take your identity, content,\
and social graph with you across any app in the Decentralized Social ecosystem.
{% endembed %}

### DeSo Featured Apps

<table><thead><tr><th width="168.33333333333331">Name</th><th width="377">Description</th><th>Link</th></tr></thead><tbody><tr><td><strong>Diamond</strong> </td><td><strong>Decentralized Twitter</strong><br>The Web3 Twitter where creators and communities engage and earn</td><td><a href="https://diamondapp.com/">https://diamondapp.com</a></td></tr><tr><td><strong>Desofy</strong></td><td><p><strong>Decentralized Social Network (Mobile)</strong></p><p>Experience the entire world of decentralized social as a mobile app</p></td><td><a href="https://desofy.app/">https://desofy.app</a></td></tr><tr><td><strong>Openfund</strong></td><td><p><strong>Decentralized Fundraising</strong></p><p>A web3 social fundraising platform for projects and online communities</p></td><td><a href="https://openfund.com/">https://openfund.com</a></td></tr><tr><td><strong>DeSocialWorld</strong></td><td><p><strong>Decentralized Social Network (Global)</strong></p><p>Experience DeSo in multiple languages across any country around the world</p></td><td><a href="https://desocialworld.com/">https://desocialworld.com</a></td></tr><tr><td><strong>DeSo Chat Protocol</strong></td><td><p><strong>Decentralized Telegram</strong></p><p>Open-source client for on-chain E2EE DMs and group chat messaging</p></td><td><a href="https://chat.deso.com/">https://chat.deso.com</a></td></tr><tr><td><strong>DeSo Wallet</strong></td><td><strong>Decentralized Wallet</strong><br>Social wallet for all DeSo NFTs, Creator Coins, Tokens, Identity &#x26; Social Graph</td><td><a href="https://wallet.deso.com">https://wallet.deso.com</a></td></tr><tr><td><strong>DeSo DEX</strong></td><td><strong>Decentralized Coinbase</strong><br>Trade DeSo Tokens (Social ERC-20) on a non-custodial order-book exchange</td><td><a href="https://openfund.com/trade">https://openfund.com/trade</a></td></tr><tr><td><strong>HeroSwap</strong></td><td><strong>Cross-Chain Swapping Service</strong><br>Cross-chain swapping service that allows for any supported currency with no login</td><td><a href="https://heroswap.com">https://heroswap.com</a></td></tr><tr><td><strong>VibeHut</strong></td><td><strong>Decentralized Google Meet</strong><br>Create magic by interacting with like-minded people on video calls</td><td><a href="https://vibehut.io/">https://vibehut.io/</a></td></tr><tr><td><strong>NFTz</strong></td><td><strong>Decentralized OpenSea</strong><br>Social-first NFT marketplace and community for artists and fans</td><td><a href="https://nftz.me">https://nftz.me</a> </td></tr><tr><td><strong>NodeBitsDAO</strong></td><td><strong>Decentralized</strong> <strong>Node Farm Rewards</strong><br>Passive crypto reward benefits of running Web3 nodes with zero server management. </td><td><a href="https://nodebitsdao.com">https://nodebitsdao.com</a></td></tr><tr><td><strong>AltumBase</strong></td><td><strong>Analytics &#x26; Insights</strong><br>Social block explorer and dashboards for the decentralized social blockchain.</td><td><a href="https://altumbase.com/">https://altumbase.com/</a></td></tr><tr><td><strong>DeSo Geo</strong></td><td><strong>Social Location Map</strong><br>See where everyone in the DeSo ecosystem is located throughout the world on a map.</td><td><a href="https://desogeo.com">https://desogeo.com</a></td></tr><tr><td><strong>DeSo Blogs</strong></td><td><strong>On-Chain Blog Aggregator</strong><br>See all DeSo blog posts published on the blockchain, categorized by topic. </td><td><a href="https://atdeso.com/blogs">https://atdeso.com/blogs</a></td></tr><tr><td><strong>Gem Stori</strong></td><td><strong>Decentralized Social Network</strong><br>Consume DeSo feeds, media, and notifications in a fast and convenient app.</td><td><a href="https://www.gemstori.com/">https://www.gemstori.com/</a></td></tr><tr><td><strong>Mint As NFT</strong></td><td><strong>Mint Tweets as NFTs</strong><br>Mint any tweet or twitter thread as an NFT directly on the DeSo blockchain</td><td><a href="https://diamondapp.com/u/mintedtweets">https://diamondapp.com/u/mintedtweets</a></td></tr><tr><td><strong>Mint Machine</strong></td><td><strong>NFT Minting Generator</strong><br>Custom generative NFT generator and minter for your NFT project using our codebase.</td><td><a href="https://diamondapp.com/u/MintMachine">https://diamondapp.com/u/MintMachine</a></td></tr><tr><td><strong>Post 2 Earn</strong></td><td><strong>Decentralized Advertising Engines</strong><br>The Post 2 Earn DAO takes advertising revenue and distributes them back to active creators for engaging on DeSo!</td><td><a href="https://post2earndao.com/">https://post2earndao.com/</a></td></tr><tr><td><strong>Buy DeSo with Stripe</strong></td><td><strong>Fiat On-Ramp via Stripe</strong><br>Buy DESO easily with fiat via Stripe onramp.</td><td><a href="https://buydeso.safetynet.social/">https://buydeso.safetynet.social/</a></td></tr></tbody></table>

> Add your project by messaging @deso on-chain: <https://diamondapp.com/u/deso>

### DeSo Ecosystem

Explore more projects, apps, and builders in the DeSo ecosystem (maintained by the community via [@mashelenn](https://diamondapp.com/posts/7392d795e098332b1740a5de2de22a9c4fea8dcb5a445cc3f62e69c66c7787cb?feedTab=Hot)):

* <https://docs.google.com/spreadsheets/d/1hLdjrfytU2pl6oPiwT4wip0I2fsI-q9zHXbN2V_UASA/edit#gid=0>

### Ideas for Potential DeSo Applications

Here are a few ideas of what's possible to build on DeSo (**fully on-chain**):

* Activity Feeds
* AI-Driven Content Creation
* Content Management Platforms
* Creator Monetization Tools
* Cross-Chain Swapping
* Curation Services
* DAO Tooling
* Decentralized Media
* Decentralized Order-Book Exchanges
* Decentralized Social Networks
* End-to-End Encrypted & Private, Token-Gated Apps
* End-to-End Encrypted Messaging & Group Chats
* Forums & Communities
* Fundraising Platforms
* Image Sharing Apps
* Internationalized Social Feeds
* Governance & Polls
* Loyalty & Referral Programs
* Long-Form / Blogging Platforms
* Music NFTs and Discovery
* NFT Virtual Ticketing & Access
* NFT Marketplaces
* NFT Minting Sites
* Notification Services
* Open-Source Algorithms
* Play-2-Earn Gaming
* Post-2-Earn&#x20;
* Q\&A / Upvoting Apps
* Social Analytics
* Social Airdrops & Rewards
* Social Betting
* Social Leaderboards
* Social Post Scheduling
* Social Sharing & Listening
* Social Wallet Apps
* Talent Discovery Platforms
* Video Sharing Apps


# Bare Metal

Social features on highly-scalable bare-metal architecture

In terms of architecture, a good way to understand DeSo is to imagine a Bitcoin node, only evolved to be able to handle a much wider array of transaction types than just sending/receiving money, with a vast amount of custom storage and indexing logic tailor-made to support social features at scale.

### Code Walkthrough

For developers who are interested in diving into the lower-level specifics, [this developer guide](/architecture-overview/dev-setup) is a good starting point, and this [code walkthrough](/architecture-overview) is the best way to fully internalize how everything fits together. It may look dense, but it is written in plain English, and shouldn't take more than an hour or two to fully internalize.\
\
For non-developers, the best way to understand DeSo's architecture and its advantages is to continue to the next section, which explains things in high-level terms.

### Storage & Indexing at Scale

While traditional blockchains like Ethereum are extraordinary for creating open financial ecosystems, they are not designed to scale to handle the storage and indexing requirements of running competitive social media applications.

For example, DeFi applications typically require the updating of balance entries in-place, without creating a new "state," whereas every post on a social platform creates a new state that needs to be stored and indexed in a certain way.

Many issues like this make social media a special use case that we believe needs to be unbundled, and given its own dedicated architecture, in order to be properly served.

DeSo's biggest advantage lies in the fact that it is ***not*** a general-purpose blockchain.

Instead, it supports a narrow set of social-oriented features that it implements on bare metal, using custom indexes that every node builds during consensus when it syncs from its peers.

In contrast, general-purpose blockchains must run all functions through a virtual machine, which is typically orders of magnitude slower than running on bare metal, and even then they cannot build custom indexes for querying as they sync.

As a very simple example, consider a social transaction that updates one's username.

A node needs to check that the username is not currently held by another user before it allows this transaction to go through.

*Simple, right*? Except that when you have just a million users, this lookup becomes prohibitively expensive on even the most advanced general-purpose blockchains today.

In contrast, because DeSo can support this lookup with access to bare metal, it can cheaply and efficiently create a simple key-value index that is as fast as it would be for a centralized social application, and that can even be sharded across multiple disks or nodes as the user-base grows.&#x20;

### Advantages of Bare Metal

The advantages of bare metal only increase as usage increases and as more use-cases are considered.

For example, checking that a parent post exists before allowing someone to reply, or even checking that an NFT is for sale before allowing someone to place a bid (noting that Ethereum's lack of support for on-chain bidding has caused significant centralization and concentration to occur around NFT marketplaces).

As another simple example, consider displaying a simple list of a user's most recent posts.

Because general-purpose blockchains do not generally support ordered lists, this is not even possible without building an off-chain index.

In contrast, DeSo natively supports indexes such as posts ordered by timestamp, profiles ordered by the value of their coin, NFT bids organized by which NFT they're associated with, and much more, and all of these indexes can scale as the user-base grows.

This significantly reduces the complexity of running a node, which in turn can significantly increase the decentralization of the ecosystem, and the number of apps that can be built on top of DeSo.

As one final example, even the mempool of DeSo nodes was written from scratch to support queries for social data, without requiring users to have to wait for blocks to mine.

This seemingly minor optimization is critical in order for DeSo apps to feel "**instant**," and we believe DeSo would not be competitive with traditional centralized social apps without it.


# Scaling Roadmap

Scaling decentralized social networks with an innovative PoS roadmap

## A Simplified Scaling Roadmap

There are currently many different, and suitable, ways that the DeSo architecture can be scaled to support one billion users.

Fundamentally, as long as the feature set is kept sufficiently narrow, with an intense focus on keeping everything as close to bare metal as possible, then most of the tools and lessons of scaling centralized social platforms like Instagram can be directly applied to scaling DeSo.

The above being said, we think it's valuable to provide a scaling roadmap with calculations so that blockchain enthusiasts can take comfort in the existence of a concrete path to one billion users.

Below, we detail a concrete scaling roadmap with four relatively straightforward phases:

* **Phase 1:** Proof of Stake
* **Phase 2:** Bigger Blocks
* **Phase 3:** HyperSync
* **Phase 4:** Sharding

The math below walks through DeSo scalability at each stage:

1. **Proof of Stake**
   * DeSo moved from PoW to it's breakthrough [Revolution PoS](https://revolution.deso.com/) on **July 9th, 2024**
     * Revolution PoS brings many novel innovations including:
       * Content, Identity, Social Graphs, Finance and Assets fully on-chain & decentralized on a single Layer-1, with streamlined onboarding.
       * Support for fully on-chain Twitter-scale consumer apps at 500 posts per second, and thousands of DeFi transactions per second.
       * <1/10,00th of a cent per post compared to \~$1 on Solana and $100+ on Ethereum.

         1 second confirmation times.
       * Data synced over a thousand permissionless validators with HyperSync, and secured via on-chain E2E-Encryption where needed.
       * Burn-Maximizing Fee (BMF) model built to minimize congestion, and increase value for coin-holders.
       * State-of-the art Fast-HotStuff consensus, the first of it's kind in production.
       * Permissionlessly run validators with no staking minimums, no slashing risks, with commodity hardware (when using min. requirements).
     * You learn learn more about Revolution via [revolution.deso.com ](https://revolution.deso.com)<br>
2. **Bigger blocks**
   * The average DeSo blockchain post size is **218 bytes**.<br>
   * There are 10 other [transaction types](https://github.com/deso-protocol/core/blob/135c03a/lib/network.go#L239) besides `POST`, such as `LIKE` and `FOLLOW`. In a recent block, posts were about **1/3** of the total block size.<br>

     <img src="https://lh4.googleusercontent.com/YSLyEVtV0Ynx--mta7IP3QS5aVrZiq7MBVmIc9h9bZwbCrLXXTIIDzO2Gm9RYOjaqQONhOju-F7RvaTIVO6vWJ5AMASXIYHMI4z9sjK3acpoXOmhRHX99-35qS4I54KBl2C3zjnH" alt="" data-size="original">
   * The DeSo blockchain currently produces up to 2MB blocks every 5 minutes.<br>
   * So it can scale to \~30 transactions per second, **which is \~10 posts per second** (= 2e6 bytes/block / (218 bytes/post \* 60 seconds/minute \* 5 minutes/block) \* 1 post / 3 transactions).<br>
   * If we increase the block size to 16MB blocks every five minutes, we can roughly extrapolate that it scales to \~240 transactions per second = **\~80 posts per second**.<br>
   * For comparison, Twitter has approximately [6000 posts/second](https://www.dsayce.com/social-media/tweets-day/#:~:text=Every%20second%2C%20on%20average%2C%20around%206%2C000%20tweets%20are%20tweeted%20on,August%202014%20with%20661%20million.) on average with 300M users.<br>
   * So, at 80 posts per second, we should be able to roughly accommodate about 80/6000 = 1.33% of 300M users, or **4M users**.<br>
   * That’s where we can get with a basic block size increase alone. But we have a few other cards to play.<br>
3. **HyperSync**
   * With an Ethereum-like [warp or snap sync](https://blog.ethereum.org/2021/03/03/geth-v1-10-0/), we loosen a key constraint, which is the need for all nodes to always validate the entire history of transactions. (You can still run an archival node, but this won’t be necessary for normal operations.)
     * As a concrete example, if all you're downloading is the current creator coin balances for each user, then all that user's trades are effectively compressed into a few integers because you don't care about the history (only the end state).<br>
   * Instead, we move to a model where nodes by default first sync and validate a snapshot of the current blockchain state and then sync only a few week's worth of blocks on top of that.<br>
   * Generally, the bottleneck to blockchain performance is validation speed. With DeSo, we've run tests that indicate a node running on an Intel Xeon E-2276M can validate transactions at the rate of **\~12MB/s = 1.04TB/day = \~55,000 txns per second**.<br>
   * So, if we start by just downloading the state with minimal validation, how big can it be? To download 10TB at 10gbps = 10e12/10e9\*8/60/60 takes about \~2.2h. To download 100TB at 10gbps = 10e12/10e9\*8/60/60 is about **\~22.2h to download the state**.<br>
   * With warp sync, the block size can be increased beyond 16MB because the number of blocks required to get a node up-to-date can be reduced to only one week's worth of blocks rather than the entire history of blocks from the beginning of time.<br>
   * Let’s suppose then that using warp sync we increase the block size further to 120MB blocks. How many transactions per second (TPS) would 120MB blocks every 5 minutes facilitate? If we assume 218 bytes per transaction (which is what the value is per post), then (120e6 bytes / (5 minutes \* 60 seconds/min)) / (218 bytes/txn) = **\~1,800 transactions per second**.<br>
   * How much bandwidth would it take to synchronize one week of 120MB blocks appearing every 5 minutes, and how long would it take in wall clock time?<br>
     * Bandwidth would be roughly (120e6 bytes/block \* 1 block/5 minutes \* 60 minutes/hour \* 24 hours/day \* 7 days/week) / 1e9 bytes/GB = 238GB/ week<br>
     * At the aforementioned validation speed of 12MB/s on an Intel Xeon E-2276M, it would take approximately 238e9 bytes/week / (12e6 validated bytes / second \* 60 seconds/minute \* 60 minutes/hour) = **5.5-6 hours to download and validate one week of 120MB blocks** at a validation speed of 12MB/s on good hardware.<br>
   * Under these assumptions, This means that the warp upgrade can allow us to sync a node in \~5.5h while maintaining 1,800 transactions per second (TPS) long-term.<br>
     * 1,811 tps vs Twitter with 6,000 posts per second and 300M users (assume only posts, no likes)<br>
     * Users = 300M \* 1,811 / 6000 / 3 txns per post = **\~30M users.**<br>
4. **Sharding**
   * All transactions can then be write-sharded to make syncing a node parallelizable, thus providing multiple orders of magnitude in speedup.\
     \
     For example, we could do a very simple optimization, which is to shard all posts into their own sub-chain, and then shard other transactions across two of their own sub-chains.<br>
   * This would result in a node being capable of syncing 3x faster, meaning that we could support **\~90M users without an increase in sync time**.<br>
   * Ultimately, all transactions can be sharded into sub-chains by user ID, which would allow for virtually unlimited parallelization.\
     \
     For example, with thirty shards, we achieve another \~10x multiplier on the TPS without an increase in sync time, thus achieving **\~1 billion users**.<br>
   * This number can be scaled further by increasing the number of shards.


# Content Moderation

Creating a new open-economy of scale for moderation via global participation

### Centralized Moderation[​](https://deso-docs.vercel.app/docs/blockchain/content-moderation#centralized-moderation) <a href="#centralized-moderation" id="centralized-moderation"></a>

Moderation of content is an absolutely critical topic when it comes to building a decentralized social network, and it is probably the topic we have spent the most time on besides engineering design.

First, because all of the data on DeSo is open, an ecosystem around moderation can develop that is more robust than what can be achieved with a traditional company.

For example, because the data is open, the best machine learning researchers at the best academic institutions in the world can build APIs that label all of the content on the blockchain in a way they can't today, which can then be consumed by all node operators that want to remain compliant.

This would create an economy of scale around moderation that we believe can be more robust than what's possible within the confines of a single corporate entity.

All of the data being open also allows the Federal government to better analyze the spread of misinformation, and be more involved in preventing it, than they can be when all of the content people are seeing is locked up in a corporate walled garden.

Moreover, at a high level, we start by considering a spectrum of how decentralized the internet can be.

Right now we are on the very “centralized” side of the spectrum, where small moderation teams at a few companies control the vast majority of public discourse.

We think this is too far on one end of the spectrum, but we also think that the opposite end, where there is total anarchy with regard to content, is even worse.

### Decentralized Moderation[​](https://deso-docs.vercel.app/docs/blockchain/content-moderation#decentralized-moderation) <a href="#decentralized-moderation" id="decentralized-moderation"></a>

DeSo sits in the middle of the above spectrum. It leverages the same moderation scheme that governed the pre-Facebook internet, which we think deters harmful content without stifling innovation and competition.

Any website that displays harmful content is subject to both federal and civil litigation, whether its content comes from a blockchain or from a USB drive.

This is what prevents harmful content from seeing the light of day on the internet today, even though there are many people who could theoretically serve it.

It's also largely how the pre-Facebook internet was kept in check, and it's the same mechanism that prevents nodes on the DeSo network from serving harmful content.

For example, one of the main applications built on DeSo, [Diamond](https://diamondapp.com/) is exposing a subset of all the posts on the blockchain.

Diamond filters the blockchain content to prevent showing content that is harmful or illegal. Every node that runs on top of the DeSo blockchain, including apps like Diamond, Pearl, or Desofy, can expose whatever subset of the posts that they want.

This being said, showing illegal or harmful content would not only subject them to copious amounts of litigation, but it would also likely make it such that nobody would want to use them.

That content will still technically be on the blockchain but it won't be practically accessible.


# Infinite-State

The incredible cost advantages of storage-heavy blockchains

Many believe that general-purpose blockchains like Ethereum, Cardano, Avalanche, and Solana will come to power everything on the web, including financial apps, social apps, and even Amazon-like marketplaces.

But there's a show-stopping problem that's being widely overlooked: **on-chain storage**.

While today's general-purpose blockchains have worked well for storage-light applications like DeFi, they cannot scale to handle storage-heavy applications like social apps and marketplaces.

Imagine a world in which every "like" or "follow" on a decentralized app cost $1.00+ in storage fees.

Unfortunately, that is the reality now because of the storage limitations of all general-purpose blockchains on the market today.

### Storage Costs[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#storage-costs) <a href="#storage-costs" id="storage-costs"></a>

The numbers don't lie. The simple table below illustrates how the cost of storing just 1 gigabyte of on-chain state varies across blockchains. Importantly, these costs are only expected to increase for general-purpose blockchains, as they become more popular and storage becomes more scarce.

We will discuss DeSo as a special case later on.

<figure><img src="https://uploads-ssl.webflow.com/6148aea00f7f907469e373ad/618492a6cae2196583f44adb_DESO_blog%20graphics_FINAL_7pm.png" alt=""><figcaption><p>Pricing snapshot taken as of Nov 09, 2021. Make sure to check out the Appendix for detailed calculations.</p></figcaption></figure>

These high on-chain storage costs prevent the vast majority of web 2.0 applications from being implementable on today’s general-purpose blockchains, even if using bridges to storage-focused blockchains such as Arweave or Filecoin.

At current prices, even storing a single link to Arweave or Filecoin on any of the chains shown above would cost between $0.10 - $1.00+, which is prohibitively expensive.

And the costs are likely going to go up even more as these chains become more popular because they weren't designed to scale state storage.

Moreover, even though many blockchains claim to be able to handle thousands of transactions per second, aka TPS, this metric does not take into account the storage properties of the application at hand.

There is a big difference between 50,000 DeFi transactions, which may generate zero bytes of new state data, as opposed to 50,000 social transactions, which may generate tens of megabytes that need to be stored, indexed, and queried.

Today's most advanced blockchains fail completely at handling the latter type of transaction, and this limitation is blocking the development of some of the most interesting Web3 applications.

We've been researching this challenge for years, and we believe that all storage-heavy Web3 applications, such as social apps and marketplaces, will require new types of blockchains to develop.

That is because, as we will discuss, these applications are infinite-state applications rather than finite-state applications.

### From Finite-State to Infinite-State[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#from-finite-state-to-infinite-state) <a href="#from-finite-state-to-infinite-state" id="from-finite-state-to-infinite-state"></a>

Today, all general-purpose blockchains on the market were built to power what we call finite-state applications.

These are applications where the amount of data or state that you have to keep on hand for each user is, well, finite.

For example, in order to build a financial app, all you really need to know in order to validate transactions is each user's account balance.

Users could transfer funds between each other millions of times, but in the end, all you need to store is just a few numbers indicating the final balance of each user.

Put another way, the state you have to keep around grows as a function of the number of users rather than as a function of the number of transactions. Perhaps surprisingly, virtually all of decentralized finance, aka DeFi, consists of finite-state applications.

As long as you can store a handful of account balances, you can start to build arbitrarily-complex tools for people to trade, borrow, lend, etc... and you'll never have to store more than the ending balances in the long-term.

This is because the transactions users perform in DeFi applications are state-neutral transactions, meaning they simply modify existing balances rather than append new data to the state.

The problem is that, as blockchains look to disrupt applications beyond the financial sector, they start needing to deal with a completely different class of applications: the infinite-state applications.

**Now, what if we want to look beyond finance?**

Infinite-state applications are ones where the amount of data you need to store grows indefinitely with the number of actions that each user performs.

For example, consider a typical social app.

* Users can create a profile, which adds state...
* Users can make a post, which adds state...
* Users can follow other users, which adds state...
* Users can like posts and comments, which adds stats...

You get the picture.

The difference is that with social applications, all transactions are "*state-augmenting*" rather than "*state-neutral*", as is the case with DeFi.

With social apps, instead of just having to keep a few account balances in your state, you need to be able to store an indefinite amount of data.

Even worse, this state needs to be frequently queried by other users on the network, requiring it to be highly-available. Unfortunately, many applications we use today are like this, including most social apps and marketplaces.

What's more, as we'll discuss, none of the existing general-purpose blockchains on the market today are equipped to handle these types of applications.

### Congestion of General-Purpose Chains[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#congestion-of-general-purpose-chains) <a href="#congestion-of-general-purpose-chains" id="congestion-of-general-purpose-chains"></a>

All the general-purpose blockchains on the market today, including Ethereum, Cardano, Avalanche, Solana, and others are ill-equipped to handle infinite-state applications such as social apps and marketplaces.

This is because scaling infinite-state applications, even to a small number of users, requires solutions that are inherently tailored to the storage and indexing requirements of the app at hand.

> **Remember:** 50,000 state-neutral transactions per second — is not the same as — 50,000 state-augmenting transactions per second.

For example, most of the newest general-purpose blockchains on the market maintain high TPS by storing all account state in memory.

This doesn't just work great for finite-state applications like DeFi, but it is the optimal choice if you want to be the fastest DeFi blockchain.

However, the second someone tries to build an infinite-state app on your chain, you go from having to store a single number for each user, to having to store potentially megabytes or more, which means things suddenly don't fit in memory anymore.

Moreover, if the blockchain is general-purpose, it can't make intelligent decisions about what account state is needed in-memory vs what isn't, and it certainly can't index the data to make it query-able in real-time.

The end result is that all general-purpose blockchains today have had to impose storage limits in order to remain viable. This has resulted in skyrocketing storage fees that make it prohibitive to build infinite-state apps on them, and that will only worsen as these chains become more popular.

Nobody is trying to build infinite-state applications on a general-purpose blockchain because it's impossible to do so at a low enough cost.

But there's a whole world of interesting applications that are infinite-state. In fact, the vast majority of Web 2 applications are infinite-state (FB, Insta, Amazon, etc).

So how can Web3 take off if you can't even build the majority of Web 2 applications on today's finite-state chains?

Moreover, all it takes is for a single person to build an infinite-state application on a general-purpose blockchain before its storage becomes congested.

To use an analogy, imagine you're sharing a dorm room with three other roommates-- if a single one of them is messy, then your room gets filled with clutter.

Similarly, building a full-scale social app or a marketplace, even on one of the newer general-purpose blockchains, will immediately hit these blockchains' inherent storage limits, causing all infinite-state apps to become virtually unusable relatively quickly.

We have already seen this tragedy of the commons play out with Ethereum and it's starting to happen on Solana as well.

### Scaling Infinite-State Apps[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#scaling-infinite-state-apps) <a href="#scaling-infinite-state-apps" id="scaling-infinite-state-apps"></a>

In order to handle the storage and indexing requirements inherent to infinite-state applications, we believe blockchains will need to be built that are custom-tailored to the application at hand.

This is because, without being able to make assumptions about the type of data that will be stored, *aka the schema*, the costs of storing, indexing, and querying the data will skyrocket, making applications built on the chain uncompetitive.

To give a very concrete example, consider the Decentralized Social blockchain, aka DeSo. DeSo is custom-built from the ground up to power social applications, and that means that all of the data that it stores and indexes follows a known schema.

Profiles are stored and indexed differently than posts, which are stored and indexed differently than follows, etc...

This level of customization not only makes storage costs **10,000x cheaper** than Avalanche or Solana, but it also allows all DeSo nodes to offer instant querying of all relevant data.

Queries like figuring out who liked a post or figuring out who someone follows, which would be expensive if the data was stored in an unstructured way, are virtually instant.

This makes it much easier for developers to build apps on DeSo, and it is part of the reason why there are already over a hundred apps built on it, including Diamond, Pearl, Desofy, DeSocialWorld, Stori, and more.

The simple table below illustrates how the cost of storing just 1 gigabyte of on-chain state varies across blockchains.

Note also that, as time goes on, the storage rents of the general-purpose chains are expected to increase as storage becomes scarce. In contrast, DeSo's costs are expected to remain fixed, and potentially even decrease, since it was built to handle the infinite-state use-case.

Interestingly, even though the DeSo blockchain was designed to support social applications, it is important to note that it can be augmented to support any infinite-state application, as long as the schema is well-defined.

The key is that each new type of application is supported at the bare metal level and customized in such a way that the storage and indexing requirements of that application are optimized.

This means that, over time, as a network effect forms around the DeSo blockchain, it can be extended to support marketplace data structures and more, giving it the potential to disrupt all of Web 2.0, and not just the social media giants.

### Other Storage Blockchains[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#other-storage-blockchains) <a href="#other-storage-blockchains" id="other-storage-blockchains"></a>

It is important to mention that there are also blockchains that have focused exclusively on storage, such as Filecoin or Arweave.

Some have suggested that these blockchains can be used in combination with a general-purpose blockchain in order to alleviate the storage issues they face.

In practice, however, the storage costs of general-purpose blockchains are so high that even storing a simple link to Filecoin or Arweave for each piece of content would cost between $0.10 - $1.00+ at today's prices.

This makes it prohibitively expensive to build most infinite-state apps using these bridges, and the cost will only increase as these chains become more popular.

Additionally, data stored in Filecoin or Arweave would not be indexed appropriately, and thus a whole separate indexing layer would need to be created in order to support each app at scale. The indexing layer would then need its own incentive structure in place as it becomes more and more expensive to run at scale.

The above being said, Arweave can be useful for storing data that does not need to be indexed, aka blob storage, and the DeSo blockchain allows for images and videos to be stored on Arweave if the user desires.

The DeSo blockchain then stores a link to Arweave as opposed to storing the image on-chain or in a centralized service.

Notably, because the cost of storing links on DeSo is virtually free ($0.0000184), DeSo can integrate these systems in a way that today’s general-purpose blockchains cannot.

### Conclusion[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#conclusion) <a href="#conclusion" id="conclusion"></a>

We think that the difficulty of storing and indexing data in a scalable way is something that has been underestimated by most of the crypto space.

For a long time, the entire space has been limited to finite-state applications without much consideration for the wide range of infinite-state applications, like social apps and marketplaces, that in fact make up the majority of Web 2.0 applications.

In order for Web3 to reach its full potential to disrupt Web 2.0 and the systems of the past, we believe blockchains that are custom-built to support new use-cases will be required because of the storage and indexing limitations inherent to the existing general-purpose chains.

### Appendix[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#appendix) <a href="#appendix" id="appendix"></a>

In this section we explain the calculations of how much it costs to store 1 GB of state data on each blockchain as of publishing on Nov 09, 2021

#### DeSo[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#deso) <a href="#deso" id="deso"></a>

In DeSo’s transaction cost model, the fee is simply the transaction size in KB multiplied by MinFeeRateNanosPerKB. The current rate is 1000 Nanos per KB, which means 1 GB of storage costs 1 DeSo. As of writing, the price of DeSo is $80. Storage costs in USD are expected to remain fixed or even decrease as the blockchain scales and efficiency increases over time.

#### Cardano[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#cardano) <a href="#cardano" id="cardano"></a>

Cost is calculated using the a + b x size formula. Taking a = 0.155381 ADA, b = 0.000043946 ADA. For simplicity, we skip the costs associated with Cardano’s Plutus execution (which would further increase the price), and instead just focus on the bare minimum transaction cost.

We assume an average state-augmenting transaction appends 500 bytes of data to the state, hence 1GB of storage would cost about 354708 ADA. As of writing, the price of ADA is $1.97, which gives a total cost of $698,775.

#### Avalanche[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#avalanche) <a href="#avalanche" id="avalanche"></a>

Cost is calculated based on today’s gas price of 25 NanoAVAX and one word (32 bytes) costing 20,000 gas or 0.0005 AVAX. For simplicity, we skip the gas costs of smart contract code execution and of allocating the storage and instead only consider the bare minimum cost of SSTORE operations. This makes storing 1GB of data cost about 15625 AVAX. As of writing, the price of AVAX is $63.24, which gives a total cost of $988,125.

#### Solana[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#solana) <a href="#solana" id="solana"></a>

Cost is calculated based on today’s rent fee of 19.05 lamports per byte-epoch and epoch lasts 2 days. For 1 GB of state, this gives the biennial rent equal to 6858 SOL. As of writing, the price of SOL is $200, which gives a total cost of $1,371,600. It’s worth noting that this is only the amount required to be rent-exempt, otherwise Solana will charge a recurring fee of 19.05 SOL every 2 day epoch.

#### Ethereum[​](https://deso-docs.vercel.app/docs/blockchain/infinite-state#ethereum) <a href="#ethereum" id="ethereum"></a>

Cost is calculated based on today’s gas price of 150 Gwei and one word (32 bytes) costing 20,000 gas or 0.003 ETH. For simplicity, we skip the gas costs of smart contract code execution and of allocating the storage and instead only consider the bare minimum cost of SSTORE operations. This makes storing 1GB of data cost about 93750 ETH. As of writing, the price of ETH is $4200, which gives a total cost of $393,750,000.


# On-Chain Data

Defending against the risk of censorship via maximum on-chain transparency

### Centralization Risks

Some would argue that social applications can get by without storing everything on-chain.

For example, one could imagine an Ethereum-based app that registers a user's public key on the blockchain initially, but then stores all posts on a centralized server.

The problem with such an app is that whoever is running the centralized server has a significant incentive to, eventually, become a gatekeeper just like the social juggernauts we have today.

This is especially true if the app is structured as a for-profit company since its fiduciary duty to its shareholders will inevitably accelerate its transformation into a closed-walled garden of content.&#x20;

Moreover, this risk means that developers building on top of this ecosystem will be deterred from ever investing in it, and even those that do will have trouble raising money.

Thus, with DeSo, we believe it is tantamount to store every piece of data we possibly can directly on the blockchain and to adjust the architecture of the chain by whatever means necessary to maintain this.

In the long-term, we believe this value will prove critical not only in ensuring that DeSo's growth surpasses that of other networks but also in ensuring that DeSo's end-state does not mirror the closed, highly-centralized social ecosystem we have today.

### List of On-Chain Data

To be concrete, below is a complete list of everything that DeSo is currently equipped to store on-chain, and the notable exceptions:

* All identity & profiles
* All posts and comments
* All private messages between users, which are end-to-end encrypted
* All likes and follows
* All social token activity
* All social tipping activity
* All NFT activity, including NFT bids
* All $DESO transfer activity
* Links to all rich media, such as video and images
* All profile verifications via a new verification paradigm called "[associations](https://diamondapp.com/u/deso/blog/associations-explained-building-network-effects-on-chain)"

**Exceptions:**

* Raw images and videos are stored in centralized but publicly accessible and easily replicable repositories, making the on-chain links sufficient to guarantee access into perpetuity.
* Emails and phone numbers are stored by individual node operators in order to protect users' privacy. We do not think this presents a significant centralization risk; however, if this proves incorrect then this information can be encrypted and stored with the profile in a privacy-preserving fashion relatively easily.
* Decisions about what profiles to show or hide, or how to curate content, lie with node operators. However, we think this is a positive force for decentralization, as we will discuss  moderation here [Content Moderation](/deso-blockchain/content-moderation)

As more features are added to DeSo, we will continue to ensure that all data that could pose a centralization risk lives on-chain.

Moreover, we believe immensely that this value will come to separate DeSo from other more centralized efforts in terms of the value that can be created.


# Smart Services

The future of cross-chain interoperability

When Brian Armstrong started Coinbase, he made a very contrarian decision:

He bet that a centralized approach to building a crypto exchange would result in a better user experience in the short-run, and therefore outcompete more decentralized approaches.

Today it seems obvious since you couldn't even build a decentralized exchange back then, but at the time it was heresy.

The decision to build a centralized crypto product was so contentious that Brian [broke up with his first co-founder](http://wired.com/2014/03/what-is-bitcoin/) over it. In the long run, practicality tends to triumph, but in the short run, it can be difficult to put aside ideology in favor of it.

We argue for a similarly-heretical viewpoint: **We believe that most of the computation that smart contracts are built for today will happen off-chain in centralized but composable smart services, as we will describe them.**

Blockchains will still be useful for storing **assets** and **content**, but we believe **computation** will move almost entirely off-chain.

This is because smart services will allow Web2 developers to build without having to learn any new programming languages, will allow native inter-chain communication and composability and will scale much better than smart contracts.

These benefits come at the expense of some centralization and trust compared to smart contracts, but we believe developers, and the market more broadly, will strongly prefer smart services to smart contracts in spite of this.

### Smart Contracts are Hard[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#smart-contracts-are-hard) <a href="#smart-contracts-are-hard" id="smart-contracts-are-hard"></a>

Today, if you want to write Web3 applications, most people in the space will tell you to write smart contracts.

To write them, you won't just have to learn a new programming language, like Solidity or Rust, but you'll have to adapt to a whole new "event-driven" programming paradigm that is rife with gotchas.

After you've learned how to write code and deal with all the gotchas, you still have to minimize storage because smart contract chains are not equipped with robust, cost-effective storage and indexing capabilities.

And even then, once you have a working smart contract, it's limited to a single blockchain. An Ethereum smart contract can't directly call an Avalanche or Solana smart contract, and vice versa.

Smart contracts are really hard for most developers, and we think they've made the barrier to entry for getting into Web3 much higher than it needs to be.

What's more, the lack of interoperability and composability across chains has further hindered what developers can build.

*We think there's a better way.*

Specifically, a way of achieving the same functionality that smart contracts give you, but using solely Web2 APIs and Javascript/Python, which millions of Web2 developers are already familiar with.

Can you imagine how much more building there would be if you could build apps with tools already widely-understood by millions of Web2 developers?

What's more, what if your code could seamlessly tap into all blockchains at once, even blockchains that don't natively support smart contracts, like Bitcoin?

We call this new paradigm **smart services**, and we believe they will come to power the vast majority of Web3 applications, effectively replacing smart contracts as the dominant way for developers to build.

Why? Because, as we will discuss, smart services do a much better job of maximizing developer accessibility, interoperability, composability, and scalability than smart contracts do.

### On-Chain vs Off-Chain: The Epic Debate[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#on-chain-vs-off-chain-the-epic-debate) <a href="#on-chain-vs-off-chain-the-epic-debate" id="on-chain-vs-off-chain-the-epic-debate"></a>

Before going into the details behind smart services, it's important to note that, at a high level, smart services trade off decentralization and censorship-resistance for enhanced **developer accessibility**, **cross-chain interoperability**, **composability**, and **scalability**.

This really hits on a more existential question for the blockchain space, which is:

When is it useful to use a blockchain vs doing things on a centralized Web2 server?

As time wears on, more and more of crypto is starting to move off-chain.

Even with NFTs, which are a recently-popular blockchain-based product, the image/video content is nearly always stored off-chain, and auctions are generally all done off-chain as well.

But where will this trend lead us? For example, will Instagram one day host NFTs in a totally-centralized way, the same way they host images and videos today? We don't think so — not quite at least.

Generally, as the future of Web3 unfolds, we think that **assets** and **content** will be stored on-chain, while **computation** will move off-chain, effectively rendering smart contracts far less useful than they are today.

For example, we believe your tokens, your NFTs, and your social graph will benefit significantly from being on-chain. But computation-based services that allow you to lend, trade, stake, etc. will move off-chain into smart services.

In light of this, there are a few reasons we believe blockchains will continue to be useful:

* **Censorship-resistance.**
  * When assets and content are stored on a blockchain, no one company or app can freeze someone's assets or censor their voice. This seems to imply that users will prefer to have important assets like their tokens ultimately stored on a blockchain, even if they use smart services for computations like swaps, crowd sales, or loans.<br>
* **Portability.**
  * Although smart services can interoperate via Web2 APIs, putting your assets on a blockchain virtually guarantees that they will be accessible to you and to third-party developers forever. It also means that a token or post on one smart service will show up in all other smart services in much the same way assets like Bitcoin can move between cryptocurrency exchanges today.<br>
* **Overcoming regulatory constraints.**
  * By eliminating reliance on a centralized party entirely, blockchains can sometimes satisfy regulatory requirements that centralized services cannot. For example, issuing tokens or NFTs on a blockchain can provide extra protection against securities law concerns.

### Web2 Developers[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#web2-developers) <a href="#web2-developers" id="web2-developers"></a>

The above being said, although the benefits of storing things on-chain may seem strong, we believe that the ease of development that smart services provide to Web2 developers makes it much harder to justify using a blockchain in general for anything other than the most important pieces of state that the users need to store.

Why? Well, think about it: If smart services only require the developer to know Javascript and Web2 APIs, then we're tapping into a pool of millions of developers who can't even contribute to web3 yet because they don't know Solidity or Rust.

Given the option of writing a smart service for the first time, we believe the vast majority of these developers will choose to compromise on the blockchain advantages listed above when it comes to the computation piece of their app in favor of moving fast and shipping their product, just like Brian Armstrong did with Coinbase so many years ago.

Moreover, who would you rather bet on to find Web3's killer app:

An army of millions of Web2 developers writing unconstrained javascript — or thousands of Solidity/Rust developers operating under gas optimization constraints?

Given the above, one might reasonably ask: What will smart contracts remain useful for if a lot of computation moves into off-chain smart services?

Generally, we think smart contracts will be useful in defining new standards for assets and content, such as ERC-20 (tokens) or ERC-721 (NFTs).

If you want to do something with an Ethereum token, for example, you will still hit an ERC-20 smart contract on the Ethereum blockchain to move assets around, even if the fancier computations are happening in your smart service.

However, as time wears on, it is important to note that smart contract blockchains will start to compete with custom-built blockchains like DeSo that outperform smart contract implementations on efficiency.

Thus, while smart contracts will likely remain useful vehicles for discovering new blockchain-based products, we think there is a significant risk that apps in need of high throughput will eventually shift their assets and content to blockchains that customize themselves to the scaling needs at hand.

### What is a Smart Service?[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#what-is-a-smart-service) <a href="#what-is-a-smart-service" id="what-is-a-smart-service"></a>

Let's break down our understanding of a smart service.

![Smart Services](https://uploads-ssl.webflow.com/6148aea00f7f907469e373ad/61d5bfa51ac5554fd45895d6_Deso%20Mocks-05.jpeg)

Smart service might seem like a fancy term, but we're really just referring to a simple centralized web service that conforms to a certain set of basic constraints.

These constraints, as we will discuss, allow for discoverability and interoperability between smart services regardless of which underlying blockchains they're tapping into. We list these constraints below.

Any web service that satisfies the bullets below would count as a smart service, regardless of whether it's written as a NodeJS server or using a popular web framework like Django:

* A smart service has a traditional Web2 domain name that other services can use to call it, `e.g. mysmartservice.com`
* A smart service has a REST API implementing, at minimum, the following critical endpoints:

#### `/get-address`[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#get-address) <a href="#get-address" id="get-address"></a>

* Every smart service has at least one on-chain wallet that is identified by an address or public key. This allows the smart service to accept funds from users and to do arbitrary things with them the same way an on-chain smart contract would.<br>

  The `/get-address` endpoint is defined by all smart services, and it simply returns the address that users can send funds to in order to interact with the smart service.

  Put another way, the `/get-address` endpoint makes smart services discoverable to one another.<br>

  Importantly, smart services are not bound to a particular blockchain. If a smart service wants, it can return multiple addresses, each one corresponding to a different chain.<br>

  Users can then send ETH to the Ethereum address or DESO to the DeSo address with the assumption that the smart service will do the right thing in each case. Not all smart services will do this, but they have the option to do so.<br>

  Deposits into the smart service's address can include a generic key-value metadata map that will be utilized by the `trigger()` function described below.

#### `/get-info`[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#get-info) <a href="#get-info" id="get-info"></a>

* Returns a key-value map with important information about the smart service. This can also include a simple description of how the smart service works and what it's supposed to do.

  Smart services can implement other functions via additional REST API endpoints.<br>

  Standards can then be defined to introduce interoperability around smart services that implement well-known functions (note that the value of smart services is more about ease of development than it is about standardization of APIs).<br>

  Deposits into the smart service's address can include a generic key-value metadata map that will be utilized by the `trigger()` function described below.

#### `trigger()`[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#trigger) <a href="#trigger" id="trigger"></a>

* A smart service defines a `trigger(metadata)` function that can be written in any language that is automatically called every time a deposit is made to one of the smart service's addresses, as returned by `/get-address`.<br>

  The `trigger()` function gets a metadata argument associated with the deposit that includes the raw transaction, the deposit address, and the amount deposited.<br>

  The `trigger()` function is the magic of the smart service framework. Normally, a developer would have to scan the blockchain for transactions they're interested in, which is challenging, time-consuming, and inefficient.<br>

  With a smart service, everything is set up so that the `trigger()` function is called whenever a relevant transaction is detected, so all the developer has to do is fill it in.<br>

  This function is not technically required, but it's essential to how most smart services will function. Namely: someone deposits money, then the smart service does something.<br>

  It also causes smart services to be directly analogous to smart contracts in terms of how they function, making them familiar to existing smart contract programmers.<br>

  Again, the `trigger()` function could also operate in a totally cross-chain fashion, e.g. enabling DESO to move between wallets when ETH is sent to the smart service's ETH address.<br>

  As the smart services framework matures, developers can start substituting a generic `trigger()` function for event handlers such as `onETHDeposit()` or `onNFTTransaction()` that make the code even easier to write and reason about.

### Examples[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#examples) <a href="#examples" id="examples"></a>

The best way to understand the smart service framework is to walk through a couple of simple examples.

#### Example #1: Token Swap Smart Service[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#example-1-token-swap-smart-service) <a href="#example-1-token-swap-smart-service" id="example-1-token-swap-smart-service"></a>

Imagine you want to implement a smart service that allows someone to deposit ETH and immediately have that ETH exchanged for DESO, and vice versa.

Below is what this smart service would look like:

* The service would run at a domain name like `desoethswapper.com`
* `/get-address` would be implemented, and would return the smart service's ETH and DESO addresses.
* `/get-info` would return the instructions for using the smart service via a key-value map. This map can also include important info like the current exchange rate the smart service is offering between DESO and ETH, any fees it's charging, etc.
  * **description**: Call `/get-address` and send DESO to the DESO address to swap to ETH, send ETH to the ETH address to swap to DESO.
    * Include the destination address in a key named `destination`. The exchange rate is specified in the `/get-info` call and indicates the amount of DESO you will receive per ETH."
  * **exchange\_rate**: 5.0
  * **smart\_service\_type**: "swapper"
    * This field allows other smart services to make assumptions about the behavior of the smart service. More on this later.
    * The `trigger(metadata)` function would be defined roughly as follows in any language, including Javascript or Python:

```
if depositAddress == DESODepositAddress:
  EthAmountToSend = metadata['amount'] / exchange_rate
  EthDestinationAddress = metadata['destination']
  Send EthAmountToSend to EthDestinationAddress

else if depositAddress == ETHDepositAddress:
  DESOAmountToSend = metadata['amount'] * exchange_rate
  DESODestinationAddress = metadata['destination']
  Send DESOAmountToSend to DESODestinationAddress
```

Once a smart service like this is defined, anyone can call it to swap ETH for DESO and vice versa.

All you need is the domain name, `desoethswapper.com`, and then the `/get-info` call tells you how to use the service.

Once you know how to use the service, you simply send funds with the appropriate metadata to one of the smart service's blockchain addresses, which you can get from the `/get-address` endpoint.

What's more, the behavior of a swapper smart service can be standardized to the point where any smart service that identifies itself as a swapper in its `/get-info` call can be composed with any other smart service.

For example, anyone can spin up a Uniswap-like aggregator smart service that combines all the swapper smart services into a clean UI.

Then, if you want to swap currency A for currency B, the Uniswap-like smart service can route your trades through whatever smart services clear your order the most efficiently.

#### Example #2: Crowdsale Smart Service[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#example-2-crowdsale-smart-service) <a href="#example-2-crowdsale-smart-service" id="example-2-crowdsale-smart-service"></a>

Suppose you have an ERC-20 token that you've created, let's call it `$MYDAO`, that you want to sell in some clever fashion for DESO.

That is, you want people to deposit DESO into your smart service and get $MYDAO coin out of it.

What would such a smart service look like?

* First, it would have a Web2 domain name. Let's say it's `mydaocrowdsale.com`
* `/get-address` would simply return the DESO address of the smart service, since this smart service only accepts DESO.
* `/get-info` would describe the terms of the crowdsale, and tell users what metadata needs to be included.
  * **description**: Call `/get-address` and send DESO to the address returned in order to purchase `$MYDAO` coins.
    * Include your `$MYDAO` address in the metadata of your deposit with the `destination` key. The price doubles for every million `$MYDAO` coins sold.
    * The current price of `$MYDAO` as denominated in DESO is returned in the exchange\_rate field: `exchange_rate: 10.0`
  * **smart\_service\_type**: "crowdsaler"
* `trigger(metadata)` would be called on each deposit, and would fulfill the user's purchase.

Its logic would look as follows:

{% code overflow="wrap" %}

```
// Track ToenAmountSold as a global variable outside of the trigger() function so
// so that it can be referenced and incremented as the sale progresses.
// ---
// The exchange rate will be computed based on the amount of the token that has been // sold.

TokenAmountToSend = computeTokenAmountToSend(metadata['amount'], TokenAmountSold)
TokenDestinationAddress = metadata['destination']
Send TokenAmountToSend to TokenDestinationAddress

// Update the amount sold, which will increase the exchange rate for subsequent
// purchases.

TokenAMountSold += TokenAmountToSend
```

{% endcode %}

Clearly, arbitrarily complex crowdsales can be implemented by simply modifying the `trigger()` function.

Moreover, these crowdsales can clearly span multiple blockchains, meaning that someone could raise money for their project using ETH, even if what they're selling is a DESO token, and vice versa.

#### Example #3: ERC-20 Smart Service[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#example-3-erc-20-smart-service) <a href="#example-3-erc-20-smart-service" id="example-3-erc-20-smart-service"></a>

As discussed, because smart services are more centralized than smart contracts, we think they will initially be preferred for computation rather than assets and content.

This means that an ERC-20 token may still be better off on a blockchain like Ethereum or DeSo (via DeSo Tokens), since that would make the balances of its holders portable and censorship-resistant.

The above being said, just to highlight the power of smart services, we think it is important to note that even an ERC-20-like standard could be defined entirely as a smart service that implements standard token transfer functions as REST API endpoints (`/total-supply`, `/balance-of`, `/allowance`, `/transfer`, `/approve`, and `/transfer-from`).

If your smart service implemented this set of endpoints, your smart service could then integrate seamlessly into a Uniswap-like "aggregator" smart service to allow trading of your smart service's token.

You could then plug the Web2 domain name of your smart service into the Uniswap smart service, and the Uniswap smart service would know how to call the standardized REST API endpoints of your smart service in order to enable trading.

Again, the Uniswap smart service would not be bound to a particular blockchain. It could theoretically allow trading across a diverse array of assets across chains in a totally agnostic way.

Moreover, an ERC-20 that is defined entirely as a smart service would not be subject to high gas fees that ETH-based ERC-20 tokens are subject to.

### Deploying Smart Services[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#deploying-smart-services) <a href="#deploying-smart-services" id="deploying-smart-services"></a>

Because smart services can be written and deployed in any language, there is technically no required way to deploy one. You can deploy a web service however you want, and as long as its API is accessible on the internet, other smart services will be able to discover and interoperate with it.

The above being said, we are working on a "one-click deploy" functionality that will allow one to fill in simple Javascript functions, and then have that code instantly deployed to a platform like Firebase.

In the long-term, one can imagine that the Javascript code itself gets automatically deployed to a hosting platform, abstracting away deployment and making the code fully descriptive of the smart service's functionality.

Such a platform can enforce that code that is deployed matches what is actually running in the smart service, yielding even stronger guarantees than smart contracts today.

Competition among smart service hosting providers should be highly-competitive and thus fairly decentralized in the long run in much the same way Web2 hosting is today.

### A Note on Layer-2 Solutions[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#a-note-on-layer-2-solutions) <a href="#a-note-on-layer-2-solutions" id="a-note-on-layer-2-solutions"></a>

Ethereum layer-2 solutions like Arbitrum or ZK-Rollups achieve similar scalability improvements as smart services and improve on trustlessness, but they do so at the expense of being much more difficult to build apps with than smart services.

For example, you cannot write a customized ZK-Rollups app using solely Javascript and Web2 APIs.

As such, layer-2 solutions do not engage millions of existing Web2 developers the way that smart services do, which is where we believe most of the value of going off-chain will come from.

### Conclusion[​](https://deso-docs.vercel.app/docs/blockchain/smart-services#conclusion) <a href="#conclusion" id="conclusion"></a>

Smart services outperform smart contracts on **developer accessibility**, **interoperability**, **composability**, and **scalability** at the expense of centralization.

We believe that this makes smart services much more appealing to developers, which makes it highly likely that the killer apps will start to be built on smart services going forward, rather than smart contracts.

Once this starts to happen, we believe blockchains will be used predominantly to store assets and content with computation moving off-chain into smart services.


# User Security

Not your keys, not your content

## **What is a seed phrase?**

Your seed phrase is the password that controls your entire account. Your seed phrase can never be changed and sharing your seed phrase with anyone could result in total loss of funds.

## **Do DeSo applications have access to my seed phrase?**

No, if you're using DeSo Identity Service, applications do not have access to your seed phrase.&#x20;

Your seed is stored in your browser in a highly-secured `iframe` that is completely isolated from the rest of the app. Transactions are signed in your browser by this `iframe` and **your seed phrase never leaves your browser.**

## **How do I keep my account safe?**

For maximum security, the developer community recommends you use mobile browsers or the DeSo desktop app to access DeSo applications.

Both mobile browsers and the DeSo desktop app are secured, sandboxed environments that cannot be easily compromised by third-party attackers.

While DeSo applications are generally safe to access in a regular Desktop browser like Chrome, Safari, Firefox, etc, there is some risk that malicious browser extensions could steal your seed phrase if you give them access to DeSo applications. **This should be rare, but if you own a large amount of DeSo it is recommended that you either disable extensions manually or use Incognito mode, which disables extensions automatically.**

Furthermore, if you own a large amount of DeSo it may be prudent to create two separate accounts: one account that you use to post and follow, and a separate account to hold your coins.&#x20;

## **What do I do i**f I lose my seed phrase?

Because your seed phrase is stored exclusively in your browser, it cannot be recovered by any third party. **If you lose your seed phrase, currently the only option is to create a new account, save the new seed phrase, and send all of your holdings to this new account.**\
\
You may need to liquidate your creator coin holdings into DeSo first. You can transfer a username by first changing the username on the old account and then quickly claiming the username with the new account.

We apologize for the inconvenience here. We know this process is not ideal, but we're working on alternative solutions, and hope to have an easier recovery path for users in the future.

## How does DeSo Identity work?

DeSo Identity, located at [identity.deso.org](https://identity.deso.org), safely stores your sensitive account information in your browser's local storage. To protect private key material the identity service has minimal dependencies, a strict content security policy, and is audited by multiple security firms.\
\
**For now, the developer community does not recommend entering your seed phrase anywhere other than identity.deso.org.**\
\
Always check the URL bar to verify you are using `identity.deso.org.`

The DeSo Identity Service aims to make it easy for users to use a wide array of community projects safely and securely.\
\
Apps and nodes can integrate with DeSo Identity to onboard users without requiring them to enter private key material. Users can easily grant different levels of access on a per-account basis.


# Associations

A social network can be visualized as an undirected graph with users and posts acting as nodes and their interactions acting as the edges connecting them.

An “*association”* is a transaction type on the DeSo blockchain to embody those edges to help connect this graph.

There are two types of associations:

1. **User associations**
2. **Post associations**

And in total, we've introduced **4 new distinct transaction types** on the DeSo blockchain to support associations:

* *CREATE\_USER\_ASSOCIATION*
* *DELETE\_USER\_ASSOCIATION*
* *CREATE\_POST\_ASSOCIATION*
* *DELETE\_POST\_ASSOCIATION*

A simple way to think of this relationship is that 1) user associations connect a user (*the transactor*) to another user (*the target user*), and 2) post associations connect a user (*the transactor*) to a post (*the target pos*t).

In addition to the transactor and the target user or post, associations have three customizable fields:

1. The association type
2. The association value
3. The application scope

The association type allows associations to be a polymorphic data structure, representing multiple different kinds of relations between users and other users or users and posts.

The application scope allows an association to be specified either within the scope of a single application or globally across all applications on the DeSo blockchain.

### **User Examples**

Associations are easiest explained using a few example use-cases.

Let’s start with **user associations.**

User associations can be used to endorse other users, similar to the skills endorsement feature available on LinkedIn.

Imagine **User A** wants to endorse **User B** for knowing the programming language “JavaScript” on Diamond.

**User A** can submit the following association transaction:

![](https://images.deso.org/398599c540928a7983b7107939dcbf1e81c07a0a48348da47cd348f63ea9ff41.webp)

This association acts as an official on-chain endorsement by **User A** of **User B**’s knowledge of “JavaScript”.&#x20;

This is non-spoofable because, like all transactions on the DeSo blockchain, **User A** will have to sign that payload with his private key for it to be accepted.&#x20;

This allows applications built on top of the DeSo blockchain to then query using the DeSo API for all of the users who **User A** has endorsed or all of the users who have endorsed **User B** for knowing JavaScript.

Other user association use-cases we have in mind that are now enabled include reporting users, flagging users, blocking users, user stats & scoreboards, and provable / gateable group membership. We’ll talk more about this later.

### **Post Examples**

Let’s also consider an example **post association.**\
\
Currently, the DeSo blockchain allows for a user to submit a LIKE transaction to “thumbs up” a post. However, Associations will allow them to submit *any reaction* on a post.

For example, imagine **User A** would like to HEART **User B**’s post globally across all applications. Or maybe react with a thumbs-up, an upvote, a downvote, a smiley face, a crying face, or any other popular emoji.

**User A** can submit the following association transaction:

![](https://images.deso.org/0cbd84466205c7f53a44fb9af221fb66095e598e7b83da8539638048c4a98eec.webp)

Applications built on top of the DeSo blockchain can query for the number of reactions on **User B**’s post, all of the users who have hearted the post, etc.

Other post association use-cases we have in mind that are now enabled include flagging posts, reporting posts, and tagging posts as e.g. NSFW.

One could imagine a Reddit clone now being built on top of the DeSo blockchain leveraging user associations to specify moderators and post associations for those moderators to tag posts by their subreddit.

And best of all, all of the other DeSo features come for free like single sign-on, tipping, NFTs, DeSo Tokens, the DeSoDollar stable coin, etc.

### **Infinite Use-Cases**

Notice that the **association type** and **association value** attributes of an association can be any user-defined string. So there are infinite possibilities for associations beyond the examples described above.

And the DeSo API allows for advanced querying to slice-and-dice on-chain associations to power all kinds of applications.

In this way, with a single new transaction type on the DeSo blockchain, we have enabled infinite new possibilities for storing generic key-value data relating users and posts on-chain, all for very cheap as DeSo boasts incredibly low transaction fees.

Let’s take a look at even more concrete examples of how associations can be used:

#### **Reactions**

Currently, users can LIKE a post, but associations now enable apps to allow any arbitrary reaction on a post such as thumbs up, thumbs down, happy face, heart emoji, laughing face, crying face, etc.

* **Association Class:** *User*
* **Transactor:** *The user doing the reacting*
* **Target Post:** *The target post being reacted on*
* **Association Type:** *REACTION*
* **Association Value**: *THUMBS\_UP | THUMBS\_DOWN | HEART | LAUGH | CRY …*
* **App**: *Can optionally scope post reactions to a single app*

#### **Moderators**

Associations can be used to assign moderators of an application. They can more generically be used to build out an entire on-chain application’s roles-rights permission system.

* **Association Class**: *User*
* **Transactor**: *The app’s public key*
* **Target User**: *The user being granted permission*
* **Association Type**: *ACCESS\_ROLE*
* **Association Value**: *ADMIN | LEVEL\_1 | LEVEL\_2 | LEVEL\_3 …*
* **App**: *App’s public key*

#### **Tagging Posts**

Associations can be used to arbitrarily tag posts. These tags can then be used to sort + moderate content.

* **Association Class**: *Post*
* **Transactor**: *The user doing the tagging*
* **Target Post**: *The* *post being tagged*
* **Association Type**: *TAG*
* **Association Value**: *NSFW | Sports | Business | Technology …*
* **App**: *Can optionally scope post tags to a single app*

**Subreddits**

Combining the moderator and tag use-cases above can enable an on-chain Reddit clone. Users can submit posts and tag them as belonging to a specific subreddit, e.g. r/bitcoin&#x20;

The app can assign moderators who can then perform some admin functionality like blacklisting posts or users. And users can upvote or downvote posts within each subreddit.

#### **Reporting, Flagging, Blocking Users**

Associations allow for users to report, flag, or block other users. Applications can then use this information to e.g. block a user from the app if enough individual users report.

* **Association Class**: *User*
* **Transactor**: *The user doing the reporting, flagging, blocking*
* **Target User**: *The user being reported, flagged, blocked*
* **Association Type**: *REPORT | FLAG | BLOCK*
* **Association Value**: *This can optionally provide a reason for reporting, flagging, or blocking*
* **App**: *Can optionally scope the action to a single app*

#### **Reporting, Flagging, Hide Posts**

Associations allow for users to report, flag, or hide posts. Applications can then use this information to e.g. hide posts.

* **Association Class**: *Post*
* **Transactor**: *The user doing the reporting, flagging, or hiding*
* **Target Post**: *The post being reported, flagged, or hidden*
* **Association Type**: *REPORT | FLAG | HIDE*
* **Association Value**: *This can optionally provide a reason for reporting, flagging, or hiding*

#### **Facebook-Style Friend Requests**

Associations enable applications to allow for users to send friend requests to each other. The application can then query if a user is a friend and can gate content to e.g. only-friends, or close friends, etc.

#### **1. Friend Request**

* **Association Class**: *User*
* **Transactor**: *The user requesting the friendship*
* **Target User**: *The user whose friendship is being requested*
* **Association Type**: *FRIEND\_REQUEST*
* **Association Value**: *REQUEST*
* **App**: *Can optionally scope a friend request to a single app*

#### **2. Friend Request Approval**

* **Association Class**: *User*
* **Transactor**: *The user who is approving an existing friend request*
* **Target User**: *The user who originally requested the friendship*
* **Association Type**: *FRIEND\_REQUEST*
* **Association Value**: APPROVE
* **App**: *Can optionally scope a friend request approval to a single app*

#### **Instagram-Style Follow Request**

Following the exact REQUEST → APPROVE pattern for Facebook-Style Friend Requests above, associations allow for users to submit and approve follow requests.

Applications can gate content to only their followers.

The association looks identical to the above except the association type would be FOLLOW\_REQUEST instead of FRIEND\_REQUEST.

#### **Facebook-Style Groups**

Associations allow for users to create groups and then gate who gains access to that group. Users can even submit requests to be considered to be allowed in.

* **Association Class**: *User*
* **Transactor**: *The owner of the group*
* **Target User**: *The user being allowed into the group*
* **Association Type**: *GROUP\_MEMBERSHIP*
* **Association Value**: *The group name, e.g. Harvard University Alumni*
* **App**: *Can optionally scope group memberships to a single app*

#### **LinkedIn-Style Endorsements**

Associations allow for users to endorse other users for specific skills, exactly like the feature on LinkedIn.

* **Association Class**: *User*
* **Transactor**: *The user doing the endorsement*
* **Target User**: *The user they are endorsing*
* **Association Type**: *ENDORSEMENT*
* **Association Value**: *The skill they are being endorsed for, e.g. SQL | JavaScript | Marketing | Public Speaking*
* **App**: *Can optionally scope endorsements to a single app*

#### **Polls**

Associations allow for users to submit a post with poll options and then users to submit their poll response.

* **Association Class**: *Post*
* **Transactor**: *The user responding to a poll*
* **Target Post**: *The post which contains the poll*
* **Association Type**: *POLL\_RESPONSE*
* **Association Value**: *The poll response, e.g. YES | NO*
* **App**: *Can optionally scope poll responses to a single app*

#### **Game Scoreboards**

Associations allow for games to store their daily user leader scoreboards on-chain.

For example, consider a daily Wordle challenge where the game wants to store the user and how many tries it took them to guess the word to then display a daily leader scoreboard.

This is possible with associations:

* **Association Class**: *User*
* **Transactor**: *The game app’s public key*
* **Target User**: *The user who received the high score*
* **Association Type**: *2023-01-26\_HIGH\_SCORE*
* **Association Value**: *Their score, e.g. 4*
* **App**: *The game app’s public key*

DeSo will introduce a set of recommended standards for applications to reference.\
\
We hope this demonstrates the power of what associations can achieve and we can’t wait to see what new possibilities developers unlock.


# Creator Coins

## Blockchain-Native Social Features

At launch, the DeSo blockchain supports not only traditional social features like creating profiles and posts, but also novel blockchain-native features like social tokens, tipping, and NFTs.

These features alone enable vast new categories of money-enabled products, from social NFT experiences to influencer stock markets.

These products in turn can allow creators to earn orders of magnitude more money on DeSo-enabled apps than on traditional social networks, while maintaining a more direct relationship with their followers.

Moreover, creators aren't locked-in to a handful of centralized apps with DeSo because the business model of DeSo revolves around transactions flowing through a decentralized network of potentially thousands of third-party apps, similar to how Ethereum works today for DeFi applications.

We believe this more decentralized business model can come to replace the traditional ads-driven business model for social media, which inherently requires concentrating users into a few highly centralized apps in order to maximize profit.

### What are Social Tokens? (aka Creator Coins)

#### Everyone Has a Coin

Every profile on the DeSo gets its own coin that anybody can buy and sell.

We call these coins “**creator coins**,” and you can have your own coin too simply by creating a profile. The price of each coin goes up when people buy and goes down when people sell.

#### You Can Buy Your Favorite Person’s Coin

To buy someone’s coin, you simply navigate to their profile on any DeSo app, such as diamondapp.com, and hit “Buy.”

You can find someone’s profile either by searching for it or by visiting the creator coin leaderboard (shown below).

![](/files/-Mk3a5rFSqZT16juIeD7)

### What Are Creator Coins Useful For?

Creator coins are a new type of asset class that is tied to the reputation of an individual, rather than to a company or commodity.

They are truly the first tool we have as a society to trade “social clout” as an asset. If people understand this, then the value of someone’s coin should be correlated to that person’s popularity.&#x20;

For example, if Elon Musk succeeds in landing the first person on Mars, his coin price should theoretically go up.

And if, in contrast, he makes a racial slur during a press conference, his coin price should theoretically go down.

Thus, people who believe in someone’s potential can buy their coin and succeed with them financially when that person realizes their potential. And traders can make money buying and selling the ups and downs.

The above being said, there are many other exciting opportunities for creator coins that we hope will be integrated in the very near future:

#### **The Stakeholder Meeting**

A creator can make it so that only people who own a certain amount of their coin can participate in the comments section of their posts.

This forces anyone who wants to have a voice in that creator’s content to first align themselves with the creator by buying their coin.

The alignment not only reduces spam significantly, but it could bias conversations to be significantly more positive than on existing platforms.

It would also create a lot of demand for one’s coin — can you imagine if Elon Musk or Vitalik Buterin did an AMA with a minimum threshold for buying their coin in order to participate? Or if they answered questions in order of coin holdings?

#### Premium Messages

Most creators get a torrent of spam in their social media message inboxes.

With DeSo they could make it so that only people who own a certain amount of their coin can message them, or they could simply rank and prioritize messages from the largest holders of their coin.

Alternatively, they can make it so that a certain amount of their coin must be paid to them directly in order for the message to actually enter their inbox.

All of this would increase demand for their coin while helping to minimize spam for the creator.

#### Sponsored Posts

Creators can have an “inbox” where anyone can “bid” to have them repost (aka “retweet”) a particular post.

If you want Kim Kardashian to retweet your fashion brand, you can submit an entry into her inbox, and if she retweets it then she keeps your money.

The bids can all be made using the creator’s own coin, thus significantly increasing the demand for the coin.

#### Premium Content

People who own a certain amount of a creator’s coin get access to special content. Or, alternatively, people must pay a monthly subscription in the form of the creator’s coin in order to get premium content.

#### Distributions and Engagement

Creators can also use their coins to distribute scarce resources to the largest holders of their coins.

For example, imagine if a famous celebrity offered to have lunch with whoever held most of their coin on a particular date.

Or imagine if they were going to offer 1,000 signed posters to their 1,000 largest holders.

This is just the beginning of how creators can engage with their fans using their coins, and all such ideas could increase demand for their creator coin significantly.

#### Money Likes

Likes can be re-imagined as purchases of the creator’s coin.

So it costs money to like something, but you get that person’s coin when you do so (effectively as a shortcut to buying their coin that’s associated directly with their content).

Such a feature could serve as a stronger signal on what content is high quality as well.

#### Emergent Phenomena

What can happen when you give people the ability to speculate on a person’s reputation?

We can’t know for sure, but one feature that has emerged is what we call “buy and retweet.”&#x20;

Ordinarily, retweeting someone gives you nothing.

If that person becomes a superstar because you boosted them, you’ll be lucky if they even remember your name in a few years.

In contrast, with DeSo you can buy someone’s coin and then retweet them, which makes it so that you’re not only along for the ride financially if they blow up, but you also get bragging rights.&#x20;

Imagine the difference between being able to say “I retweeted her early on” vs being able to say “I bought her coin when it was $5 and now it’s $5000 — and by the way, I’ve done this hundreds of times, and I can prove it because my track record is on the blockchain.”

The interesting thing about this mechanic is that it wasn’t even something consciously designed into the product. It exists as an “emergent” phenomenon off of the core creator coin mechanic.&#x20;

What other dynamics could exist that we haven’t yet thought of?

### The Creator Coin Supply Curve

Creator coins are naturally scarce, with generally fewer than 100 to 1,500 coins in existence for each profile.

This is because as more people buy a profile’s creator coin, the price of the coin goes up automatically at a faster and faster rate. This means that, eventually, it would take billions of dollars to mint even one more coin.

The formula or “curve” for determining the price of a creator’s coin is as follows. Note that creator coins are normally bought and sold with the DeSo cryptocurrency, but we provide a dollar version of the formula for easy calculation:

$$
price\_in\_deso = .003 \times creator\_coins\_in\_circulation^2 \ price\_in\_usd = .003 \times creator\_coins\_in\_circulation^2 \times deso\_price\_in\_usd
$$

When you create a profile, there are initially zero coins in existence and thus the price is zero.

If you want to buy coins from the profile, it will happily mint them on-chain and sell them to you according to the price curve above, making it more and more expensive as more coins are purchased.

The money you use to buy the coins gets “locked” in the profile in exchange for the coins. On the flipside, if you want to sell coins, the profile will happily buy them from you according to the curve using the money locked from previous buys.

And so buying **creates** coins while pushing the price **up** and **locking** money into the profile, while selling **destroys** coins while pushing the price **down** and **unlocking** money from the profile.

This is often referred to as an “automated market-maker,” or AMM, and it’s the same concept that powers protocols like Uniswap and Bancor.

Below is a graph of what the creator coin price curve looks like as a function of how many creator coins are in circulation for a given profile.

We also include a table that shows some of these values. Both of these assume a DeSo price of $16.

Note also that “integrating” the price curve yields the amount of money “locked” in a profile, which is equal to the “net” amount of money that has flowed into that particular creator coin (included as the third column of the table).

If you’d like to play with the numbers yourself, you can do so using [this sheet](https://docs.google.com/spreadsheets/d/1ecMscQTY4rhmfrAn-5SRspiZqhhttVo1Pj880A4EDuo/edit?usp=sharing) (make a copy to edit it). You can also learn more about bonding curves [here](https://yos.io/2018/11/10/bonding-curves).

| **Creator Coins in Circulation** | **Creator Coin Price (USD)** | **USD Locked in Profile** |
| -------------------------------- | ---------------------------- | ------------------------- |
| 5                                | $1.20                        | $2                        |
| 10                               | $4.80                        | $16                       |
| 20                               | $19.20                       | $128                      |
| 40                               | $76.80                       | $1,024                    |
| 80                               | $307.20                      | $8,192                    |
| 160                              | $1,228.80                    | $65,536                   |
| 320                              | $4,915.20                    | $524,288                  |
| 640                              | $19,660.80                   | $4,194,304                |
| 1280                             | $78,643.20                   | $33,554,432               |

![](/files/-Mk_V1xGymPeQx_5tbhp)

### Founder Rewards

Every profile allows the creator to keep a certain percentage of the coins that are created as a “founder reward.”

For example, if someone sets their founder reward percentage to 10% and then someone buys 100 DeSo of their coin, then 10 DeSo would go to the creator’s wallet rather than the purchaser’s.

The above being said, we think the better way for creators to own a piece of the upside of their coin is simply to buy their coin up-front when they create their profile, and then set their founder reward percentage to zero.

This works because the coins are cheapest at the beginning of the curve, and it has the upshot of reducing friction on subsequent purchases of their coin.

Nevertheless, the founder reward percentage being 10% is a “sane default” that guarantees creators will maintain a certain percentage of their coin even if they do nothing.


# Feeds & Moderation

## Running a Node

Running a node gives you full access to the DeSo firehose. Access to every profile, post, follow, creator coin trade, etc... But what can you do with all this power?

### **Running your own feed**

When you run a node, it starts with a blank global feed and an "Admin" panel that you can use to start adding posts to it.\
\
All of the same tools that the [Diamond](https://github.com/deso-protocol/docs/blob/main/diamondapp.com) team uses to manage their global feed are now available to you to manage a feed of your own. Essentially, running a DeSo node allows you to expose your own "view" of the firehose of content. \
\
[Diamond](https://diamondapp.com) exposes all of the crypto-related content, but when you run your own node you have full control to surface whatever content speaks to you.\
\
What will you do with your feed? Here are some ideas for feeds that we think would be popular:

* **A feed for every country and every language.** Isn't it weird that people all over the world consume information curated predominantly by the US? \
  \
  How much does an engineer working in Silicon Valley really know about what people in other countries want to see, or what features they want?\
  \
  In the past, we were stuck with this model because US companies built a data network effect that entrenched them, even in non-US countries.\
  \
  But DeSo can break this status quo because all of its data is open and the barrier to entry to starting a competitive feed is virtually zero.\
  \
  For the first time, people who actually live in a country can curate a feed for their people, no matter how large or small their country is.\
  \
  And this applies to every country that succumbed too quickly to the network effects of the Silicon Valley tech companies. By lowering the barrier to entry to creating a feed, and opening up the data firehose to anyone, we think DeSo has the potential to bring international social media products to a whole new level.<br>
* **The politics-focused feed.** It is entirely possible to create a node that prioritizes political content. Imagine a feed where all the posts from the top political figures are highlighted.\
  \
  You could even imagine segmenting the firehose into two feeds: a "red" feed and a "blue" feed that's dedicated to each political party.<br>
* **The sports-focused feed.** Wouldn't it make sense for someone to operate a feed that just highlights all of the best sports content from the best sports influencers?\
  \
  So many people are interested in this content, and we think it deserves its own feed.<br>
* **The NSFW feed.** Not all platforms will show NSFW content in their feed, for example because their user-base is too mainstream. This bias against NSFW content is even stronger with incumbent social media companies.\
  \
  Yet there are so many talented adult influencers on the DeSo blockchain, with thousands of followers, who are posting every day. It's about time they had their own feed dedicated to them.

We're just scratching the surface here — it's now up to you, the community, to figure out how best to display the DeSo firehose.\
\
Reddit pioneered the concept of a "subreddit," but the problem with a subreddit is that every time one is created, it has to solve a "chicken and egg" problem with regard to its content.\
\
If nobody is posting, then the subreddit has no content — but without content, nobody will start posting.\
\
DeSo basically takes the subreddit concept to the next level by solving the "content" part of the equation for everyone. When you run a node, you don't need to bootstrap content because you have full access to the DeSo content.\
\
All you need to do is curate it in some interesting way and you'll have created value for anyone who visits your node.

### Add social to your platform

Suppose you're a platform with millions of users like Coinbase or Robinhood, or even traditional media companies like ESPN. Your users would probably love it if you could integrate a social component into your products — but you can't because Twitter and Facebook don't allow it.\
\
They [closed down their APIs](https://theverge.com/2018/8/16/17699626/twitter-third-party-apps-streaming-api-deprecation) a long time ago because they realized that third-party integrations eat into their ad revenue. Every user who engages on a third-party platform is a user who's engaging less on Twitter and Facebook.

With DeSo, you don't need to build a billion-user data moat in order to be able to add social features to your platform.\
\
All you need to do is run a DeSo node, and use its API to expose whatever content you want. Suddenly, with just one engineer's worth of effort, any major platform can spin up a social product that's adjacent to its core business.\
\
Moreover, it's possible that the best feeds will come from existing publishers that have already built a competency in a particular area.\
\
For example, ESPN might be the best entity to run the sports-focused feed because of their relationships and connections, and now they can.

### Analysis tools

Building the best analysis tools requires access to the best data, and running a node is the best way to get full access to the DeSo firehose.\
\
Until now, the DeSo nodes have had to set up rate limits to avoid having our machines get overloaded.\
\
But now, because DeSo is a blockchain that allows anyone to run a full copy of the platform, anyone who wants to build analytics tools can simply run a node and query it in whatever way they want.

### Invent your own features

When you run a node, you have the flexibility to expose the DeSo content in whatever way most resonates with your users.\
\
We recommend starting with the frontend source code provided by the DeSo Foundation, but if you wanted to, you could even build a whole new frontend with totally different features than what the "default" node gives you.\
\
If you feel like DeSo ecosystem is missing a feature, like dark mode, paid messages, or better filtering for spam for example, now you can build it and run your own node to back it.

### Making Money on Your Node

Incentives are key to making DeSo truly decentralized in the long run. It's not sufficient that nodes be runnable by the community, they must be *profitable* to run as well. Many cryptocurrencies struggle with this, and even Bitcoin and Ethereum nodes are still largely run by volunteers.\
\
DeSo is truly unique in this regard, however, because the social features it introduces give node operators incentives that other blockchains don't have.

The above being said, there are several ways that DeSo node operators can earn a profit:

* **Promoted content.** Because running a node comes with the ability to have a social media product with minimal marginal effort, every node operator has an opportunity to amass and monetize the reach that comes from curating a popular feed.\
  \
  This can be as simple as showing promoted posts that partners pay the node operator to pin to their feed.<br>
* **Trading fees.** Anyone who runs a node can modify their frontend to add trading fees on every creator coin trade, which go to the node operator's wallet. By doing this, any node operator basically doubles as a crypto exchange.<br>
* **Other transaction fees.** Any transaction users complete on one's node can be augmented to contain a small fee that goes to the node operator. Thus there should eventually arise an efficient market for node operator fees that are high enough to justify operating a node.

The above mechanisms don't even factor in profits that could be derived from augmenting the DeSo feature set.\
\
For example, if someone creates an app experience for DeSo that is significantly better than alternatives, they could even charge a monthly subscription fee or some other premium to cover costs.

### How to Run a Node

Running a node currently requires a modest amount of technical know-how. For full instructions on how to run a node, check out this GitHub repository:

* <https://github.com/deso-protocol/run>

Once a node is running, it syncs all of the blocks from its peers, as well as the transactions in the "mempool," which have yet to be mined into a block.\
\
Every node comes with an Admin panel with a Network tab that allows you to monitor the node's sync state.

![](/files/-Mk_V1xM5jpLPbVj9WWG)

Once your node is synced, you have access to the full firehose of DeSo data in real-time!\
\
Below are some tips on how to take full advantage of your node.

* Go to your Admin tab and watch the unfiltered feed update as your node syncs. It's like a time machine!
* Try to whitelist some posts in the Admin tab and see that they've made their way onto your global feed.
* Read through the flags available in the [dev.env](https://github.com/deso-protocol/run/blob/main/dev.env) file. You can adjust these flags however you want, but note that we strongly recommend keeping your node in read-only mode for now. Turning read-only mode off could cause users who visit your node to make transactions that are not ultimately confirmed.
* Set `ADMIN_PUBLIC_KEYS` to your public key so that the Admin tab is only visible to your username.
* Set `SUPER_ADMIN_PUBLIC_KEYS` to your public key so that the Super Admin tab is only visible to your username.
* Whitelist some posts and verify that they show up on the global feed.
* Deploy your node on any cloud provider with a static IP to make it accessible to anyone on the internet.
* Set a `PASSWORDS_FILE` if you want to restrict read access to your node.
* Add an `SSL_CERT_DIR` and `SSL_DOMAIN` using a letsencrypt cert in order to protect your node with HTTPS.
* Set the `TWILIO*` flags to allow new users to get some starter $DESO.
* Set a `SUPPORT_EMAIL` so your users can contact you if they run into trouble.
* Play with the logging verbosity by increasing `GLOG_V`.

### Managing Your Feed

To manage your feed, start by navigating to the Admin tab as shown below.\
\
The Admin tab shows the full firehose of posts in real-time, with a button next to each one that allows you to add it to the global feed. \
\
These are all the same tools that the [Diamond](https://diamondapp.com) mods have, now at your fingertips through the power of decentralization.

![](/files/-Mk6-1vIjAZU__FSX_r3)

You can also add any post from anyone's profile to the global feed simply by hitting the dropdown at the top-right of the post.\
\
You can also pin posts to your feed, which is a good way of communicating announcements to your user base.

![](/files/-Mk5t9kZGi1Wgtn8Pu2z)

When you run a node, you act as a moderator and have a variety of superpowers that help you manage spam and harmful content.

* **Blacklisting** a profile removes it everywhere except peoples' wallet pages. This makes it so that anyone who was holding the blacklisted profile can sell out of their holdings.<br>
* **Graylisting** a profile removes it from the leaderboard, removes it from search, removes its comments from threads, and removes its posts from the Admin panel.<br>
* **Whitelisting** a profile makes that user's posts show up on the global feed automatically with some frequency (currently it allows five posts per day).<br>
* Finally, a mod can allow a phone number to be re-used to claim starter $DESO. This is useful for various testing situations.

![](/files/-Mk54dJ9rOIY_pVr7Tb6)

When you've set your public key as an `ADMIN_PUBLIC_KEY`, the Admin tab becomes visible only to you. This is a critical step in securing your node. Not doing this would make it so that all your users can add posts to the global feed.

### Super Admin Public Keys

Within the Admin Panel, there is a `Super` tab that is only accessible by Super Admins. Super Admin can manage user verification and $DESO purchasing behavior from the `Super` tab.

#### Username Verification

Super Admins can grant verification badges (on their node) to a user by putting the username in the `Grant Verification Badge` input box and then clicking `Verify`.\
\
Similarly, a Super Admin can revoke verification by putting the username in the `Remove Verification Badge` and then clicking `Remove`.

![](/files/-Mk54hKOL1-Yp0hB6lLh)

#### Buy $DESO Management

Any node can sell $DESO if they set the following flags appropriately.\
\
Super Admins can set two values in the `Super` tab to manage the price at which $DESO is sold on their node: `USD-to-DeSo Reserve Price`and `Buy DeSo Fee Rate`.

![](/files/-Mk54lwGk9RXmfcVQ41R)

**USD-to-DeSo Reserve Price**

This is the minimum price at which you are willing to sell $DESO on your node. If the price retrieved from exchange APIs is lower than this amount, your node will sell $DESO at this reserve price instead of the API price.\
\
Additionally, the price in the right sidebar will appear as reserve price in the event that the price from the API dips below the reserve price.<br>

**Buy DeSo Fee Rate**

This is a percentage-based fee applied to all $DESO purchased on your node. If the current price of $DESO in USD is $100 and the `Buy DeSo Fee Rate` is 5%, the buyer will pay $105 per $DESO and the node operator has earned $5 net.\
\
For more details on configuring your node to sell $DESO, please read the section titled `Sell $DESO on your node`.<br>

### Sell $DESO on your node

To simplify the onboarding experience for new users on your node, you can sell $DESO for Bitcoin directly to users. To configure your node to sell $DESO, please set the following flags:

* `BUY_DESO_SEED`: This is a seed phrase for the public key that contains $DESO that you will sell to users. As with all seed phrases, keep this secret and share it with nobody. Take extra precautions to not commit it to version control and quickly move funds if this seed is ever compromised.
  * You will need to deposit $DESO to the public key for this seed phrase. All $DESO purchases on your node will send $DESO from this wallet.
* `BUY_DESO_BTC_ADDRESS`: This is a Bitcoin address you control. When users purchased $DESO with Bitcoin, the Bitcoin will arrive at this address.

### How Users Login

When a user logs in on your node, they have the ability to sign in with their DeSo identity, without having to re-enter their seed phrase.\
\
Once a user signs in, your node can sign transactions on their behalf with varying levels of approval required depending on what kind of permission the user granted.\
\
This creates a login mechanism for node operators that is as easy for users as "login with Facebook," but it unlocks a wallet in addition to a user's identity.

### Node FAQ

Answers to common questions and issues about running your own node:

#### What are the minimum requirements for syncing a node?

We recommend having a machine with at least 32GB of RAM and 350GB of storage (as at 21 July 2021). If TXIndex is disabled, then you need about 200GB in total. The Blockchain DB takes up about 90 GB, and the TXIndex takes up 160 GB. THe DB+TXindex size grows by about 50GB a month currently.

#### How do I configure SSL?

There is an example SSL configuration in `nginx.dev`.

#### How do I use the BlockCypher API?

BlockCypher will help prevent double-spends in the mempool. You can signup for a [BlockCypher](https://www.blockcypher.com) account on the BlockCypher website. BlockCypher does offer a free amount of API calls.

Once you have signed up for an account you may copy a token from the [tokens](https://accounts.blockcypher.com/tokens) section of the dashboard.

You will copy this token in your `dev.env` file as the value for `BLOCK_CYPHER_API_KEY`.

#### What type of records do I use with custom domains?

You must create two seperate **A** type domain records.

Both records should point to the IP address of your node.

**Example DNS Records:**

| Hostname          | Type | TTL | Priority | Content     |
| ----------------- | ---- | --- | -------- | ----------- |
| node.`DOMAIN`.com | A    | 299 |          | `IPADDRESS` |
| api.`DOMAIN`.com  | A    | 299 |          | `IPADDRESS` |

If you do not create both records you will be unable to use a custom domain.

#### Can my node write back to the mainnet?

Yes! Every transaction is broadcast to all other nodes on the network, and should eventually be mined into a block.

#### What does Twilio provide to my node?

Twilio provides an SMS API that allows you to confirm user phone numbers and thus send them currency from your seed wallet set inside the `dev.env` file. If you do not have this set users will be unable to verify a phone number.


# Social NFTs

## What are Social NFTs?

Non-Fungible Tokens (NFTs) are digital assets that can be bought and sold, typically representing a piece of digital content.

For example, an artist can publish a digital image as an NFT, and put it up for sale to the highest bidder.

When they do this, the history of who owns the image can be tracked on the blockchain as a way of showing the art piece's provenance. And even though anyone in the world can typically see the image, there is only one person who provably owns it, just as if the piece were a painting hanging in a museum.

The easiest way to really understand NFTs, though, is to actually look at some examples.

Below we list examples of popular NFT concepts, as well as popular NFT platforms, all of which served as the inspiration for the DeSo NFTs product.

Importantly, because DeSo is an inherently social platform, we anticipate the use cases for NFTs will extend far beyond just digital content, and we discuss this in detail in the next section.

**Examples of popular NFT concepts:**

* [Beeple's collage](https://www.theverge.com/2021/3/11/22325054/beeple-christies-nft-sale-cost-everydays-69-million)
* [CryptoPunks](https://www.larvalabs.com/cryptopunks)
* [Bored Apes](https://boredapeyachtclub.com)
* [CryptoKitties](https://www.cryptokitties.co)
* [NBA Topshots](https://nbatopshot.com)

**Popular NFT marketplaces:**

* [OpenSea](https://opensea.io)
* [Nifty Gateway](https://niftygateway.com)
* [Rarible](https://rarible.com)
* [SuperRare](https://superrare.co)
* [Zora](https://zora.co)
* [Foundation](https://foundation.app)
* [Valuables by Cent](https://v.cent.co)

### The DeSo Advantage: Mixing NFTs and Social Media

When someone buys a piece of art or a collectible item, they do so in part because it brings them personal joy, but in part because they want to show it off.

A major superpower DeSo has is that every feature that's added to it has an inherent social component built-in, and NFTs are no exception.

In the case of DeSo NFTs, we have an opportunity to show off a user's NFT collection on their profile, and to allow users to engage around their NFTs via comments, likes, diamonds, and more.&#x20;

Suddenly, the act of buying an NFT shifts from a purely personal and/or economic motive to an inherently social one.

In addition, because DeSo has a native concept of identity in the form of a user's profile, the reputation of the issuer is tied into the NFT in a much more meaningful way, especially for celebrities and superstars with pre-existing brands.

This not only increases the value of DeSo NFTs, but we think it will also lead to all kinds of interesting dynamics that mix collecting, flexing, and social.\
\
Here's a list of features supported on-chain by DeSo NFTs:

<table><thead><tr><th>NFT Feature</th><th width="126.00000000000003">On-Chain?</th><th>Transaction Type</th></tr></thead><tbody><tr><td>Mint an NFT</td><td>✅ Yes</td><td>CREATE_NFT</td></tr><tr><td>Update an NFT</td><td>✅ Yes</td><td>UPDATE_NFT</td></tr><tr><td>Burn an NFT</td><td>✅ Yes</td><td>BURN_NFT</td></tr><tr><td>Bid on NFT (Auction)</td><td>✅ Yes</td><td>NFT_BID</td></tr><tr><td>Accept NFT Bid (Auction)</td><td>✅ Yes</td><td>ACCEPT_NFT_BID</td></tr><tr><td>Transfer an NFT</td><td>✅ Yes</td><td>NFT_TRANSFER</td></tr><tr><td>Accept NFT Transfer</td><td>✅ Yes</td><td>ACCEPT_NFT_TRANSFER</td></tr><tr><td>Exclusive NFT Content</td><td>✅ Yes</td><td>CREATE_NFT</td></tr><tr><td>NFT Creator Royalties</td><td>✅ Yes</td><td>CREATE_NFT</td></tr><tr><td>NFT Coinholder Royalties</td><td>✅ Yes</td><td>CREATE_NFT</td></tr><tr><td>NFT Royalty Splits</td><td>✅ Yes</td><td>CREATE_NFT</td></tr></tbody></table>

\
Below are just some examples of the possibilities on how to use DeSo Social NFTs...

#### **New NFT Use Cases**

* **Collectible ticket stubs.** If you were to sell tickets to a concert in the form of DeSo NFTs, then every attendee would automatically get a virtual ticket stub on their profile commemorating the event that their friends would get to see (not to mention the extra promo you'll get from your coin-holders!).\
  \
  Could you imagine if [@3LAU](https://diamondapp.com/u/3LAU) sold his tickets as DeSo NFTs? This mechanic could also be used to sell tickets to exclusive events like the premiere of a movie or an exclusive gala.<br>
* **Physical memorabilia: The digital collector's room**. Imagine selling a physical piece of memorabilia, like a prop from a movie set, with an NFT attached, issued by the original seller, that the buyer gets to flex on their profile.\
  \
  This turns a user's profile into an inventory of their collector's room, where you can see all of the cool things they own, both in the digital and physical world, with NFTs serving as certificates of authenticity issued and signed directly by the original seller.\
  \
  Could you imagine if someone like [@GeorgeTakei](https://diamondapp.com/u/georgetakei) from Star Trek cleaned out his closet one day using DeSo NFTs?<br>
* **Exclusive experiences.** Selling experiences as NFTs makes unique sense on DeSo.\
  \
  For example, creators with large followings can offer to have dinner or to host a Q\&A with a handful of their biggest fans by minting and selling a "one of 10" NFT. With DeSo, because NFTs are inherently social, the creator can engage their followers by asking them to comment explaining why they want to join before they place a bid.\
  \
  The creator then has full control over determining the winners, and those winners not only get to meet the creator, but they also get to sport the fact that they did on their

  profiles forever.\
  \
  Maybe [@wolfofwallst](https://diamondapp.com/u/wolfofwallst) could give Warren Buffet's charity lunch some competition!<br>
* **Exclusive unlockable digital content.** DeSo NFTs have an "unlockable" portion that only the winner of the NFT gets to see.\
  \
  This creates interesting use-cases around selling hyper-exclusive digital goods. For example, an artist can drop an album a week early as an unlockable 1/10,000 NFT such that only her true fans who win the NFT are able to listen to it ahead of time.\
  \
  This would result in extra cash flow for the artist while still allowing them to capture the same streaming revenues a week later. Could you imagine getting early access to [@thechainsmokers](https://diamondapp.com/u/thechainsmokers)' next album, and getting an NFT along with it?<br>
* **Exclusive chat groups.** Creators can offer exclusive chat groups using DeSo NFTs to gate

  access. For example, a creator can sell a 1/100 NFT such that any current owner of the NFT is able to participate in an exclusive Telegram group, weekly Zoom call, etc...\
  \
  We already saw this happening with creators like [@craig](https://diamondapp.com/u/craig), but it also makes sense for sports insiders like [@adamschefter](https://diamondapp.com/u/adamschefter).<br>
* **Interactive content.** For content creators, DeSo NFTs can be used as a way to solicit feedback from fans, or to guide the direction of content. For example, the creator of a podcast can sell an NFT where the winner gets to decide what their next episode is going to be about.\
  \
  The creator can solicit comments from users before they place their bids, and they have ultimate control over whom they choose as the winner.\
  \
  Alternatively, music artists can offer to put an NFT winner's name in a song or include them in a music video, and the winner would have the NFT on their profile to commemorate the experience.\
  \
  The creator of a movie or short film could sell producer credits in the final cut as NFTs. Could you imagine if the winner of a DeSo NFT could decide the topic for [@shaanvp](https://diamondapp.com/u/shaanvp)'s next show, or win a shoutout at the end of a [@jakepaul](https://diamondapp.com/u/jakepaul) or [@loganpaul](https://diamondapp.com/u/loganpaul) fight?\
  \
  How about a Clubhouse AMA with [@alexisohanian](https://diamondapp.com/u/alexisohanian), where the winners of a "one of 10" NFT get to come on-stage first? Or maybe we can finally get [@BennyBlanco](https://diamondapp.com/u/BennyBlanco) to bring us that DeSo Boys single we've all been waiting for, as a gloriously sought-after NFT.<br>
* **Counterfeit-proof Rolexes, Chanel handbags, etc...** Major brands have a big problem with

  counterfeiting: A real Rolex is worth much more than a knockoff, but knockoffs can often be

  so good that it's difficult to tell them apart.\
  \
  Now, imagine a solution based on DeSo NFTs whereby a luxury brand creates an official DeSo profile and offers an NFT associated with every single sale of their products.\
  \
  Now, a user not only gets digital, unforgeable proof that they own a real item, but they also simultaneously get to show off their purchase on their profile that all of their friends can see. \
  \
  Then, if they ever resell their Rolex, they can transfer the NFT along with it, allowing it to serve as a certificate of authenticity issued and digitally-signed directly by the brand, and that tracks the provenance of the item for its entire lifetime.<br>
* **Digital trading cards.** Any sufficiently well-known creator can create digital trading cards of themselves simply by issuing a "one of N" NFT.\
  \
  All they need to do is create a unique piece of artwork, like a [cryptopunk](https://www.larvalabs.com/cryptopunks) drawing of themselves, and their biggest fans can sport it on their profiles.\
  \
  Notably, each DeSo NFT has a serial number, so each one will be special, even within the same issue. [@ab](https://diamondapp.com/u/ab), could you be the first DeSo NFT trading card!<br>
* **Fine art.** Major artists have shown that NFTs are going to be a big part of the future of fine art. They not only allow anyone to enjoy the artist's work, but they also do a much better job of tracking the ownership of a piece, which means the provenance can't be forged.\
  \
  The fact that DeSo also incorporates the artist's identity, via their profile, into the minting of an NFT should, we hope, further increase the value and utility of NFTs issued by artists.\
  \
  Artists on DeSo have already been innovating extremely fast, and we're so excited to take things to the next level with DeSo NFTs. Maybe we can even get [@beeple](https://diamondapp.com/u/beeple) to finally claim his profile!<br>
* **The future of Charity.** Charities can create profiles on DeSo, just like ordinary people. When they do this, anyone can elect to send them DeSo as part of the sale of their NFT.\
  \
  For example, someone could auction off a dinner with themselves, but specify that all the proceeds will go to The Red Cross.\
  \
  They would then be able to digitally prove that the funds went to that charity. Alternatively, a charity can participate in the fun directly by issuing NFTs of their own.\
  \
  For example, a charity could issue NFTs where each one represents a particular acre of trees that will be planted. This allows the owner to show off their contribution to any cause they care deeply about, which could significantly increase the amount people are willing to give.\
  \
  It's a bit surprising that social media and charity aren't more closely linked today — but we believe DeSo can finally change that, and make giving easier and more fun than ever before.<br>
* **Owning a piece of history.** On DeSo, any post that a user makes can also be minted

  as an NFT and sold. The user who "owns" the resulting NFT can be seen as owning a piece of

  history.\
  \
  For example, if a sitting US president theoretically joined DeSo in the future and

  used it to make a monumental announcement, like the end of US COVID lockdowns, someone could own that very special post, and all proceeds could be donated to a charity of the president's choice.&#x20;

The above list is just the beginning; it's just what we've come up with so far. We can't wait to see what else the community can produce with DeSo NFTs.

In the past, NFTs and social media have been separate: You mint an NFT on some platform and then post about it on social media. Now they come together, as they were always meant to be, increasing engagement, reach, value, and monetization for creators.

### NFT Cashflows to Coin-Holders

Creator Coins are a major DeSo superpower that we are taking to the next level with NFTs.

On DeSo, a percentage of the sale of each NFT can be sent back to a creator's coin-holders as cashflow (including on secondary sales).

With this key feature, DeSo NFTs "close the loop" between a creator's activities on DeSo and the value of their coin.

Suddenly, creator coins are no longer objects of pure speculation; rather, they are directly linked to a creator's activity on the platform.

This means that, for the first time, followers can participate in a creator's growth rather than watching from the sidelines as they rise to stardom.

This has never been possible before, and it changes the relationship between a creator and their fans, from one in which fans pay for their work, to one in which they invest in the creator, and grow together.

Moreover, tying cashflows to creator coins makes it so that any creator who wants to market a new piece of content has a whole army of coin-holders that are invested in their success, and will help them spread the word.

Distribution is no longer solely the creator's job, and they don't need to sign their life away to a corporation in order to get it. Your fans are your investors and your distributors at the same time because they're economically aligned with you in a way that wasn't possible before DeSo.

Finally, and perhaps most interestingly, these cashflows do not ultimately inhere to the creator themselves; rather, in the same way a Picasso painting continues to fetch a high price after its original primary sale, a creator's NFTs on DeSo can continue to trade and produce cashflows for creator coins long after the creator is gone.

Thus, in some sense, tying cashflows to creator coins makes owning them analogous to owning a percentage of every sale of every piece of work the creator has or will ever produce on DeSo.&#x20;

Could you imagine if Picasso had a creator coin linked to all of his works?

### How DeSo NFTs Work

The easiest way to see how DeSo NFTs work is to try and create one on a DeSo app like [Diamond](https://diamondapp.com).

Very simply, the steps to minting and selling a DeSo NFT are as follows:

* Create a post, which consists of a snippet of text and an embedded image or video. All

  NFTs on DeSo start as posts, and you can turn any pre-existing post into an NFT.<br>
* Hit "**Mint NFT**" and select from the options:<br>
  * You can mint either a "one of a kind" or "one of N" NFT. In the latter case, there will be multiple winners of the same piece of content.<br>
  * The creator can set a creator royalty and a coin-holder royalty. This is a percentage of the sale that will go to the creator and to the creator's coin-holders as cashflow. This cashflow hits on every **secondary sale** of the NFT as well. The DeSo platform does not take a fee.<br>
  * Optionally, the creator can set a piece of unlockable content that only the winner of the NFT will get access to. This feature enables hyper-exclusive experiences to be built on DeSo NFTs, like one-of-a-kind songs that only the winner can listen to.<br>
* Once an NFT is minted, users can bid on the NFT. They must have enough in their wallet to cover the bid, but nothing is withdrawn from their wallet until the auction is closed by the creator. This allows users to bid on as many things as they like.<br>
* Whenever the creator is ready, they can close the auction by selecting a winner, or winners in the case of a "one of N" NFT. Importantly, the creator has full control over who gets to own their work; they don't have to give it to the highest bidder.<br>
* Once the auction is over, the winner(s) get to show off the NFT on their profile. It shows up in their NFTs tab, and it can be pinned to their main page.<br>

We didn't want to over-complicate things, and we believe this simple set of features enables all of the interesting use-cases described previously.<br>

Finally, as a means of concentrating liquidity around certain NFTs, we have designed a system that allows node operators to schedule "showcases." Showcases work as follows:

* A node operator selects a collection of NFTs that they want to showcase.
* The node operator schedules these NFTs to "drop" at a certain time.
* At the scheduled time, the new NFTs are showcased on the Home page in their own tab.<br>

Using this system, a node operator can curate a collection of NFTs every week, or even more frequently, and engage the community around them.<br>

This, in some sense, allows node operators to serve as the curators of their own digital galleries, with each drop introducing a new exhibition.


# Social Tipping

## What is Social Tipping?

Because DeSo is money-native, it can tie tipping with content in ways that no other social network can.\
\
On DeSo, the core mechanic introduced is called "**diamonds**," and it functions as a like, only it allows users to give variable amounts of money to content.

<figure><img src="/files/MppsdyxowF3bSVjny7b9" alt=""><figcaption></figcaption></figure>

In the screenshot above, a single diamond is a fraction of a penny while a six-diamond tip is \~$53.&#x20;

All of this is instant, and the receiver of the tip immediately gets $DESO in their wallet for their content. Many users already earn thousands of dollars a week off of this feature alone, and as DeSo scales, the economics will only get better.

Just to do some math, imagine a post with 1 million likes gets 100,000 diamonds, worth on average ten cents each.

That's $100,000 in pure cash from *just* the diamonds!

Moreover, users typically get a higher ratio of likes to diamonds, but we wanted to be conservative in our calculations.


# Identity: Overview

## Starter

Welcome to the **DeSo Identity Service** documentation!\
\
If you're looking to build a Web3 app on the DeSo blockchain, you will most likely want to use the DeSo Identity Service.\
\
This guide explains how Identity works and it should give you a good understanding of how to integrate it into your app. This guide is intended for a broad range of readers and assumes only a basic understanding of blockchain technology and the TypeScript language.\
\
When learning programming concepts it's always a good idea to simultaneously look at a code implementation.\
\
That's why in this guide, we will be tracing through the DeSo Protocol reference implementation located in the [frontend repository,](https://github.com/deso-protocol/frontend) under [`/src/app/identity.service.ts`](https://github.com/deso-protocol/frontend/blob/main/src/app/identity.service.ts).\
\
If you go through all of the Identity tutorials, you should be able to write a similar code to support your application. \
\
So let's get started!

## Background

Blockchains involve a lot of public key cryptography.

This is because every interaction on a blockchain occurs on a peer-to-peer basis, without relying on some central authority such as in traditional Web2 applications.

As a result, blockchains are based on communication models that eliminate trust from the equation and substitute it for the mathematical confidence of public key cryptography.

In such systems, each user has a pair of public and private keys.&#x20;

Drawing an analogy from traditional infrastructures, public keys are like usernames, and private keys work similarly to passwords. Typically, integrating these cryptographic primitives into a web or mobile application would have required significant software overhead and technical knowledge.

However, we believe that building Web3 applications should be as simple as possible, and no more complicated than building apps on the centralized web.

And so, we created the **DeSo Identity Service**.

The DeSo Identity service provides a convenient and secure way to manage user credentials (key pairs) in web and mobile applications built on the DeSo blockchain.

In fact, you've probably already encountered the Identity app when using applications powered by the DeSo blockchain.

Identity acts as a secured container that can be queried through Identity API to handle all the functionality related to users' key material.

The Identity API is located under [`https://identity.deso.org`](https://identity.deso.org).

Currently, it integrates most smoothly with web applications, which can be accomplished using our [Identity: Window API](/deso-identity/window-api) and [Identity: iFrame API](/deso-identity/iframe-api).

Integrations with iOS and Android can be done through derived keys or webview, as explained in our [Mobile Integration](/deso-identity/identity/mobile-integration) guide.

For simpler communication, the DeSo Identity Service will henceforth be referred to as Identity in this documentation.

Now check out the [Core Concepts](/deso-identity/identity/concepts) guide to get started integrating with the DeSo Identity Service.


# Core Concepts

Fundamentals of working with the DeSo Identity Service

## Basics

In this section, we will look into a web-based integration of the DeSo Identity Service. If you're an iOS or Android developer, this guide is still useful.

In addition, we recommend reading our [Mobile Integration](/deso-identity/identity/mobile-integration) guide afterwards.

Web-based applications interact with Identity in two ways:

* Embedding Identity in an [`iframe`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe)
* Opening Identity as a [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open)

In most cases, a web application will use both contexts concurrently.

A general rule of thumb when it comes to Identity APIs is that the `iframe` is used for all background requests such as transaction signing and message decryption — whereas the `window` context serves requests that require user interaction such as log in, sign up, and account management.

### Events

Both `iframe` and `window` contexts communicate with your application by emitting `message` events through [`Window.postMessage()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).

To start listening to these messages, we need to add a listener to the parent window, such as on [line #38](https://github.com/deso-protocol/frontend/blob/main/src/app/identity.service.ts#L38) in the implementation.

```javascript
window.addEventListener("message", (event) => this.handleMessage(event));
```

Here, `this.handleMessage(event)` is a function defined by the developer to handle the logic around incoming messages.

This handler function is likely the most important piece of code that you'll have to write when interacting with Identity.

When working with Identity for the first time, we recommend a simple `console.log(event)` to get a sense of how it works.

The `event.data` field will contain the payload of messages sent by the DeSo Identity Service.

### Initialize

The first message that Identity sends when it is opened is `initialize`. This message is sent in both `iframe` and `window` contexts and will require a response.

In this section, we will be assuming that we've already opened either an `iframe` or `window` context, but don't worry about it for now.

Each context has a dedicated guide explaining its inner workings in more detail, and we'll get to that later. Below is an example of the `event.data` that your event handler will receive on `initialize`.

And here's a corresponding handler logic on line [#226](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L226) in the implementation.

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {},
  method: 'initialize',
}
```

The above four fields are present in the majority of Identity messages. Let's take a closer look at each of them:

* The `id` is in [UUID v4](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_\(random\)) format and is used to identify requests/responses by Identity.<br>
* The `service` field is set to `'identity'` in every message, and should be checked in the event handler (like[ this](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L214)) to make sure the message originated from the DeSo Identity Service.<br>
* The `payload` field will contain the data sent by Identity, such as user information, signed transactions, etc. In the case of `initialize` message, it's left as an empty JSON.<br>
* The `method` field describes the message sent, which is `'initialize'` in our example.

The DeSo Identity Service **requires** a response to the `initialize` message on web-based applications.

Whether we're using an `iframe` or a `window`, the response can simply be sent by directly responding to the message event such as in lines [#187](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L187) and [#282](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L282):

```javascript
event.source.postMessage({ 
    id: '21e02080-0ef4-4056-a319-a66403f33768',
    service: 'identity',
    payload: {},
}, "https://identity.deso.org");
```

The `id` field should be set to match the `id` value present in the `initialize` message.

We set the `id` field as a string in the above code snippet, but you should set `id: event.data.id` in your code.

You may have noticed that in the example above we've added the string `"https://identity.deso.org"` at the end of the `postMessage()` call.

This specifies the target origin, or the accepted URL for the destination of the `postMessage`.&#x20;

We can alternatively pass the wildcard `"*"` to accept any URL, which is less safe, but we will use it throughout this documentation for simplicity.

However, we recommend setting `"https://identity.deso.org"` for better security.

A few quick notes about message formats:

* Messages with an `id` and `method` are requests that expect a response. (like `initialize`)
* Messages with an `id` and no `method` are responses to requests.
* Messages without an `id` do not expect a response.

Keep this in mind as you read through [Identity: Window API](/deso-identity/window-api) and [Identity: iFrame API](/deso-identity/iframe-api).

## Accounts

The DeSo Identity Service implements account management such as login, signup, and logout. Identity takes care of all cryptographic complexities related to blockchain accounts.

In addition, we don't have to deal with passwords or any sensitive data when using the DeSo Identity.

All account-related actions are performed via the `window` context API.

For now, we will solely focus on the general intuition about account management, and leave the details of each API endpoint for the guide on the [Identity: Window API](/deso-identity/window-api).

The account workflow involves the following steps:

1. App [opens](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L99) the Identity in a `window` context, with the `/log-in` [API endpoint](/deso-identity/window-api#log-in).
2. When user completes the login flow, Identity sends a response containing [`PublicUserInfo`](https://github.com/deso-protocol/identity/blob/f211503ea2420cc6e75e48683670d278cc152d8c/src/types/identity.ts#L20) that will be used when exchanging messages with the `iframe` context.
3. App [closes](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L196) the Identity `window` and stores the `PublicUserInfo` from step 2. into [local storage](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/global-vars.service.ts#L857) / database.
4. App uses `PublicUserInfo` when sending messages to the `iframe` context to handle transaction [signing](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L125), message [decryption](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L144), and other methods.
5. App might launch more `window` contexts to handle other actions requiring user interaction.

This communication pattern covers almost all of the interactions with the DeSo Identity.

In Step #2, we mentioned the cryptic `PublicUserInfo`.

This information can be thought of as secure user credentials consisting of three important fields:

* `encryptedSeedHex` is used to verify user accounts between the `window` and the `iframe` contexts
* `accessLevel` and `accessLevelHmac` information is used to verify the permission that the user has given to your application

When handling user account creation or login you will always need to deal with access levels explicitly, so we dedicated an entire section to them next.

### Access Levels

When handling user accounts in the DeSo Identity `window` context, you will always want to add a `accessLevelRequest` URL parameter to the request, such as below:

```javascript
window.open("https://identity.deso.org/log-in?accessLevelRequest=4", null);
```

The DeSo Protocol's implementation uses a `params` variable when handling URL parameters, and `accessLevelRequest` logic can be found at line [#85](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L85).

The access level request ranges from `0` to `4` and determines what actions the user has authorized your application for.

Higher permission level means higher number of authorized actions.

The available access levels are:

```javascript
enum AccessLevel {
  // User revoked permissions
  None = 0,

  // Approval required for all transactions.
  // This means no account action is authorized.
  ApproveAll = 2, /* DEFAULT */

  // Approval required for buys, sends, and sells
  // This authorizes all non-spending actions.
  ApproveLarge = 3,

  // Node can sign all transactions without approval
  // This authorizes all non-spending & spending actions.
  Full = 4,
}
```

Or, here's how the levels `2,3,4` (increasing downwards) look like in the DeSo Identity UI:

![DeSo Identity Access Level UI](/files/3ge1dytbOQFyoWe25IPk)

Access level determines which actions would require an approval from the user.

Approval here means we need to launch the Identity in a `window` context so that user can review and manually confirm a transaction.

The approval mechanism is explained in more detail in [Identity: Window API](/deso-identity/window-api#approve). You should only require access level `4` if your app really needs it.

In general, you should deliberately request the minimal permission level that fits the requirements of your application.

For an exhaustive list of `accessLevel` requirements for each action, check out our [Identity: iFrame API](/deso-identity/iframe-api) documentation.

## Transactions

Transactions are the building material of every blockchain.

When you think of transactions, you might think of them in financial terms, that is, a transaction is an exchange of money between users.

While this is true in traditional systems, in the world of blockchain transactions are actually more general. A blockchain transaction means any change to the underlying database, which is called the blockchain state.

On DeSo, this includes financial transactions, but also social transactions such as submitting posts, following users, minting NFTs, etc.

Since blockchain communication is peer-to-peer, we can't verify who made a transaction purely by looking at network information such as IP addresses.

Instead, we use cryptography to have mathematical certainty that the person sending the transaction is really the person they claim to be.

To do that we use digital signatures, which are special certificates issued by user's private key.

When integrating with the DeSo Identity Service, we don't have to worry about all the cryptographic nuances related to user keys.

Instead, we can simply ask Identity to do the hard work such as issuing transaction signatures.

### Lifecycle

Transactions on the DeSo blockchain have a three-step lifecycle:

**Construct:** The first step for a developer is to interact with the DeSo Backend API through endpoints such as `/api/v0/buy-or-sell-creator-coin` to get an unsigned user transaction.

**Sign:** The developer will then take the output `TransactionHex` from the construct step's response, which encodes the user transaction, and signs it using the DeSo Identity.

**Broadcast:** The signed transaction will be sent through the `/api/v0/submit-transaction` by the developer so that it can be added to the blockchain ledger.

In this section, we're mostly interested in the signing step.

The DeSo Identity Sevice handles the issuance of transaction signatures through both the `iframe` and `window` contexts.

The `AccessLevel` you've requested in`/log-in`, as mentioned in [#access-levels](#access-levels "mention"), will determine which transactions you can sign using the `iframe` context.

The required AccessLevel for each `iframe` API is detailed in the [Identity: iFrame API](/deso-identity/iframe-api) guide.

If the transaction you intend to sign matches this AccessLevel, you could simply ask the DeSo Identity Service to issue a signature in the background through the [`iframe` context](/deso-identity/iframe-api#sign).

This would be done by sending a `postMessage` to the `iframe` such as in line [#274](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L274).

```javascript
this.iframe.contentWindow.postMessage(req, "*");
```

Note that we're executing the `postMessage` on the iframe `contentWindow` .

We will explain the details of what belongs in the `req` variable in the `iframe` context guide, though we will essentially have to pass `method: "sign"` field, the `encryptedSeedHex,` `accessLevel`, and`accessLevelHmac` fields, and pass the `transactionHex` of the transaction we want to sign (example on line [#125](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L125)).

The response will contain either the `signedTransactionHex` , meaning the request was successful, or a `approvalRequired: true` field that will indicate we need to launch the Identity window with the approval flow.

To do so, we will launch a `window` context with the `/approve` endpoint and pass the desired transaction as URL param:

```javascript
window.open("https://identity.deso.org/approve?tx={transactionHex}", null);
```

After receiving the `signedTransactionHex`, we can then broadcast it to the network.

We will further describe the `method: "sign"` iframe API message and `/approve` window API endpoint in the corresponding API documentation.

## Messages

A crucial component of any social network is messaging.

That's why the DeSo blockchain was designed to handle messages as transactions that can be securely stored on-chain.

Messages are private and can only be read by the sender and the recipient thanks to our public key cryptographic protocols.

Consequently, messages are handled by Identity.

As an application developer, it isn't crucial to understand the messaging scheme in-depth, but we want to share a few remarks for those crypto-savvy readers in the [Protocol](broken://pages/-MjtsPMUQ3Cy0qFbx04f#protocol) subsection.

### Protocol

If you're working closely with DeSo messages or are a mobile app developer, you will most likely have to digest this subsection.

There are two implemented messaging protocols on the DeSo blockchain: legacy `V1`, and current `V2`; and we're expecting to move to a `V3` version soon.

Older blocks will still contain messages following the legacy `V1` messages so they ought to be handled differently than the `V2` messages.

If you've read our core documentation, you should remember the transaction `ExtraData` .

New message transactions will have a `V: []byte` field in `ExtraData` which should determine the used version (`1` or `2`) — if a message transaction doesn't have the `V` field, it means it's following `V1` scheme.

Here's how each version works:

* **`V1`**: (LEGACY) Messages encrypted to the recipient public key using AES-128-CTR scheme. \
  \
  Messages can be decrypted with the private key of the user specified in transaction metadata field `RecipientPublicKey`.<br>
* **`V2`**: (CURRENT) Messages encrypted to both the recipient and sender using [AES-128-CTR](https://github.com/deso-protocol/identity/blob/f211503ea2420cc6e75e48683670d278cc152d8c/src/lib/ecies/index.js#L175) scheme with shared secrets derived via [ECDH](https://github.com/deso-protocol/identity/blob/f211503ea2420cc6e75e48683670d278cc152d8c/src/lib/ecies/index.js#L100) and run through a simple [SHA256 ConcatKDF](https://github.com/deso-protocol/identity/blob/f211503ea2420cc6e75e48683670d278cc152d8c/src/lib/ecies/index.js#L23). \
  \
  Under `V1`, once a message was broadcasted to the blockchain, the sender of the message was unable to decrypt it on other devices.\
  \
  On the other hand, shared secrets are available both to the recipient and sender, so both can decrypt messages.<br>
* **`V3`**: (PLANNED) We intend to expand the `V2` scheme so it uses rotating messaging keys. Keys will be computed via HD wallet scheme with hardened derivation.\
  \
  Messaging keys can then be shared with third-party apps, specifically mobile clients, to simplify message handling.

If you're a mobile app developer using derived keys you will most likely need to implement the message encryption and decryption yourself, or rely on an existing implementation.

The best way would be to trace through the node.js example [encryption/decryption code snippet](https://github.com/deso-protocol/examples/tree/main/identity/messages-shared-secret) or look at [encryption](https://github.com/deso-protocol/identity/blob/f211503ea2420cc6e75e48683670d278cc152d8c/src/app/identity.service.ts#L203) and [decryption](https://github.com/deso-protocol/identity/blob/f211503ea2420cc6e75e48683670d278cc152d8c/src/app/identity.service.ts#L216) Identity code and recreate it in the programming language of your choosing.

If you bundle your code in a library for others to use, please do share it and we'll include it in this documentation!

Our cryptographic implementations are based on JavaScript [ECIES-Parity library](https://github.com/sigp/ecies-parity) from Sigma Prime.

### Implementation

Messages are primarily handled through the [`iframe` context](/deso-identity/iframe-api#decrypt), with the exception of mobile clients relying on derived keys.

These clients will handle messages through the `window` context. The goal of this subsection is to give you a general intuition about message handling.

We leave the communication details to the section on `iframe` API.

#### Encryption

Encryption is a process of concealing information so that only some authorized parties can read it.

In order to successfully encrypt and send a message transaction, the following steps should be taken:

1. Message text is first encrypted through the Identity by sending a request with `method: "encrypt"` to the [`iframe` context](/deso-identity/iframe-api#encrypt), as in [line #141](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L141).
2. The encrypted message is used in the Backend API to construct a message transaction via `/api/v0/send-message-stateless` endpoint.
3. After message transaction is prepared, the `transactionHex` will finally be signed by the DeSo Identity and broadcast to the network as described in the Transactions section.

#### Decryption

We previously mentioned concealing information, but what about revealing an encrypted message, or in other words, what about message decryption?

In order to read a message, we will pass the encrypted message to the DeSo Identity Service which will handle the message decryption for us.

This is done in a single step:

1. Send the encrypted message in a request to the `iframe` context with `method: "decrypt"` , as in [line #150](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L150). Check out the [Identity: iFrame API](/deso-identity/iframe-api#decrypt) API for details.

Another use-case for the `decrypt` API is decrypting unlockable text in NFTs.

To see how this can be done, we recommend tracing through the [`DecryptUnlockableTexts()`](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/backend-api.service.ts#L945) in the DeSo Protocol repository.

## Conclusion

In this document, we've outlined all the major components of integrating with the DeSo Identity.

If you've gone this far, you should have a good understanding of how the Identity works and what is required to efficiently incorporate it into your application.

Throughout this guide, we've intentionally left out many implementation details for the sake of simplicity.

If things made sense to you, it means it's a good time to dive into the other guides on the DeSo Identity. Specifically, if you're making a web-based application, you should take a look at our [Window API](/deso-identity/window-api) and [iframe API](/deso-identity/iframe-api) docs next.

If you're building a mobile application, we recommend taking a look at the [Mobile integration](/deso-identity/identity/mobile-integration) guide next.


# Mobile Integration

Integrating with the DeSo Identity on Mobile.

## Derived Keys

In the world of blockchain, user private keys are extremely sensitive information.

This is because, unlike Web2 password, private keys cannot be modified, which means that if somebody gets a hold of your private key, you're potentially **forever** vulnerable to an attack and there isn't much you can do unless you move your entire account to another private key.

We are firm believers that user primary keys should **never** be shared with third-party applications, regardless of their security practices, and so we created derived keys, which significantly lower attack vectors related to unauthorized access to user credentials.

Derived keys are impermanent and they usually automatically expire about 30 days after being issued.

Derived keys can also be de-authorized at any point, which we believe will allow for the creation of advanced security systems in the future that can mitigate the risks originating from key leakage.

After the `Transaction Spending Limit` block height is reached, derived keys will need to be authorized to perform specific transaction types as well as more specific operations for Creator Coin, DAO Coin, and NFT transaction types.&#x20;

Check out [Data: API](/deso-backend/api#transactionspendinglimitresponse) to learn how to construct the Transaction Spending Limit object.

A derived key is a pair of public and private cryptographic keys that are authorized to sign transactions on behalf of another key pair.

That is, if you hold a valid derived key of a user, you can submit a transaction signed by that derived key, and it will be regarded as a valid transaction as if it was made by that user.

This is particularly useful in mobile applications because it means you only have to interact with the DeSo Identity Service once, just to get the derived key of a user.

It also means that derived keys are extremely sensitive information and therefore should be handled in secure storage with the utmost caution, ideally by experienced software engineers.<br>

**The flow of using the derived keys is as follows:**

1. Generate a derived key by making a call to [Identity: Window API](/deso-identity/window-api#derive) window API endpoint<br>
2. Construct a `AuthorizeDerivedKey` transaction via Backend API through `/api/v0/authorize-derived-key`<br>
3. Sign the `AuthorizeDerivedKey` transaction with the derived key<br>
4. Submit signed `AuthorizeDerivedKey` transaction via `/api/v0/submit-transaction`<br>
5. (Optional) Confirm that the derived key was successfully authorized through Backend API in `/api/v0/get-user-derived-keys`<br>

### Generate Derived Key

In case your application requires offline signing e.g. when you’re a mobile client, identity can accommodate you with derived key material.

To get a derived key for a user, launch the [Identity: Window API](/deso-identity/window-api#derive) window API endpoint with a callback at:

```javascript
const derive = window.open('https://identity.deso.org/derive?callback=...');
```

Once the user completes the identity flow, you’ll receive a response containing the derived keypair.

For simplicity, we list the response payload as a JSON object; however, you'll receive it as URL parameters in a callback.&#x20;

#### Response

```javascript
{
    accessSignature: "30440220314ccf7a747922ddb6f8c26821c6f0dc65f0227e15014fb5e728f96abed841e2022033aace1f75eb35479d07273ff8bf1a959af75209743ced23939210f824d5321f",
    derivedPublicKeyBase58Check: "tBCKUx3cYyUcPnXyqLYuAfpChQHzcbzvhLTF6Xujuu5CA8hKaHPwTo",
    derivedSeedHex: "e4c515c30479d116757c56b4224022a5558af243946c075cff6ae2ec67fd3748",
    expirationBlock: 12024,
    derivedJwt: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2MzM5Mjg0MjgsImV4cCI6MTYzNjUyMDQyOH0.dvbNwcOUz2bzEMC79nyxzIJGI_3NoMUw59VAI6qdLGNy6x5YC9u0MsFcrDhuL-i8Y66gIQXq0VzgeIzNThxisg",
    jwt: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2MzM5Mjg0MjgsImV4cCI6MTYzNjUyMDQyOH0.4zyR0kgXIeO6P94TuGWbxxr3fHUoIyJWv4GGMAxP6gfz6UMwSSej85ZJe_N5JYYcvk_vHWhnj0CcXfGQtNMQ8Q",
    network: "testnet",
    messagingKeyName: "default-key",
    messagingKeySignature: "fakemessagingkeysignature",
    messagingPublicKeyBase58Check: "tBC1YLh9Rjy3fLcW1bRDcQ4PXhGocuGnsNqVJx3CESCJknkZ7LJ6mV"
    messagingPrivateKey: "fakemessagingprivatekey"
    publicKeyBase58Check: "tBCKWiTPdkGAiSd2jTx58hRh1TAGVnpeDE78eYqsghEeVFpjkGYNLk",
    transactionSpendingLimitHex: "80d0dbc3f4020205f4b00709ff8705042100000000000000000000000000000000000000000000000000000000000000000000871121032357f6e57297839516ae3fd71e76ce47e43f881e8be86877f00ec456594b10c9017b21032357f6e57297839516ae3fd71e76ce47e43f881e8be86877f00ec456594b10c9029b2021032357f6e57297839516ae3fd71e76ce47e43f881e8be86877f00ec456594b10c903ee4700022001855d9ca9c54d797e53df0954204ae7d744c98fe853bc846f5663459ac9cb7b00010a2001855d9ca9c54d797e53df0954204ae7d744c98fe853bc846f5663459ac9cb7b0003f50300"
}
```

Let’s take a look at these values:

* `accessSignature` is a proof of access, equal to an owner-signed digest of `sha256(derivedPublicKey + expirationBlock +` \
  `transactionSpendingLimitBytes)` (For more details check out [the implementation](https://github.com/deso-protocol/identity/blob/ffcb09a3ba6070d14a43c31a09f7ed0478fb2acf/src/app/account.service.ts#L109))<br>
* `derivedPublicKeyBase58Check` and `derivedSeedHex` is the derived keypair<br>
* `expirationBlock` is a future block height, and represents the expiration “date” (block) of the derived key. Derived keys expire after about 30 days.\
  \
  After that period, you will have to generate and authorize another derived key.\
  \
  To check if a derived key is valid you should compare the current block height, e.g. taken from `/api/v0/get-app-state` Backend API endpoint, with the `expirationBlock` that you can find by querying the `/api/v0/get-user-derived-keys` Backend API endpoint.<br>
* `derivedJwt` is a JWT token with a month-long timeout signed by the `derivedPublicKeyBase58Check`<br>
* `jwt` is a JWT token with a month-long timeout signed by the owner `publicKeyBase58Check`<br>
* `network`  is the network for which this derived key was generated<br>
* `messagingKeyName` is the key name used for v3 messaging<br>
* `messagingKeySignature` is the key signature used for v3 messaging<br>
* `messagingPublicKeyBase58Check` is the public key used for v3 messaging<br>
* `messagingPrivateKey` is the private key used for v3 messaging<br>
* `publicKeyBase58Check` is the public key that is the parent of this derived key.<br>
* `transactionSpendingLimitHex` is a hex string representing the TransactionSpendingLimit for this derived key.

### Authorize Derived Key

Before any signing can happen, a derived key must first be activated by submitting an [`authorizeDerivedKey` transaction](https://docs.deso.org/devs/backend-api#authorize-derived-key), containing the `accessSignature`, `derivedPublicKeyBase58Check`, `expirationBlock`, `transactionSpendingLimitHex` and `publicKeyBase58Check`.

To make the transaction, make a request to the `/api/v0/authorize-derived-key` Backend API endpoint.

If you set `DerivedKeySignature: true` when making the Backend API request, you can sign the authorize transaction with the derived key right away.

To help you get started with the `authorizeDerivedKey` transaction, we made [this node.js code](https://github.com/deso-protocol/examples/tree/main/identity/authorize-derived-key) snippet in examples repository that shows this flow.

If everything worked, you should see the derived key listed in the response to the `/api/v0/get-user-derived-keys` [endpoint](https://github.com/deso-protocol/backend/blob/f70d89a/routes/user.go#L2559) with a payload of `PublicKeyBase58Check` set to owner user public key.

Additionally, see the implementation of AuthorizeDerivedKey in the DeSo developer hub [here](https://hub.deso.org/#/user/authorize-derived-key).

While powerful, this model has a limitation.

Namely, it requires the user to have some balance to execute the `authorizeDerivedKey` transaction.

This poses a limitation as you won't be able to authorize a derived key for new users who might not have balance in their accounts.

However, in practice, there is no use for derived keys unless the user has some non-zero balance in their account. Otherwise, they wouldn't be able to submit any transactions in the first place.&#x20;

One possible remedy to this limitation is to send the `authorizeDerivedKey` transaction only when the user wants to perform an action and has sufficient balance, such as giving a like, making a follow, etc.

Another approach is to write a hook that sends the `authorizeDerivedKey` transaction in the background whenever user receives sufficient balance.

This simple background mechanism should mitigate most UX issues.

### Signing Transactions

The private key `derivedSeedHex`embedded in the response from Identity's `/derive` can be used to sign transactions on behalf of the `publicKeyBase58Check` owner.

To achieve this, you should construct transactions in the Backend API as if made by the owner’s public key.

You then need to append a field to transaction’s `ExtraData["DerivedPublicKey"]` with value set to the derived public key in compressed byte format (33 bytes array) encoded as hex string.&#x20;

Check out this node.js [code snippet](https://github.com/deso-protocol/examples/tree/main/identity/compress-public-key) in the examples repository for help with compressing the derived public key.

If you have trouble de/serializing transactions to add the `“DerivedPublicKey”` to ExtraData, you can use a backend endpoint `/api/v0/append-extra-data` and pass the hex of the transaction and the derived public key like this:

**Request**

```javascript
{
    "TransactionHex": "01049434a060acca8c05af65207c019e1052f3e29dc677125ce8a1833ac72e2b2d010102a7af43768408e8b8f5bacc8d0658f36bb27c7ecb81b88e210d7be4e54861a40bcf980c0a21669d2ac6caefa5af9c6bb60d28b30f78d918d5b5b9ee3b5ae986818dc07eee84012102a7af43768408e8b8f5bacc8d0658f36bb27c7ecb81b88e210d7be4e54861a40b0000",
    "ExtraData": { 
        "DerivedPublicKey": "03f6f5470d8df61160ccf364851c77b8b803131d3f1e8092301178e2fdcec15206"
    }
}
```

Because of intricacies with transaction fees and ExtraData, you should increase `minFeeRateNanosPerKb` to something like `12500` from `10000` when constructing the transaction.

Otherwise, you might get an error while submitting transactions indicating that transaction fee is too low.&#x20;

Once you have the transaction hex with the derived key in ExtraData, you can sign the transaction with the `derivedSeedHex` you’ve received from identity.

You can use the signing code from the `authorize-derived-key` example [node.js code snippet](https://github.com/deso-protocol/examples/tree/main/identity/authorize-derived-key).

You can also find this [example implementation](https://github.com/deso-protocol/backend/blob/f70d89a196cfc42ca3e32a1b80ed9935380a91be/routes/admin_transaction.go#L349) in Go of signing with a derived key corresponding to the admin backend endpoint `/api/v0/admin/test-sign-transaction-with-derived-key`.

Once signed, the transaction can be submitted through the `/api/v0/submit-transacton` per usual.

Note that we didn’t need to communicate with the DeSo Identity at any point in this process.

### Messages

You can use derived keys to encrypt/decrypt messages on the DeSo blockchain. For more information on our messaging protocol check out the [Broken mention](broken://pages/-MjtsPMUQ3Cy0qFbx04f#messages) section.

In order to encrypt/decrypt messages you will need to get shared secrets for each messaging partner of your user.

To get the shared secrets, you can submit requests to the [Identity: Window API](/deso-identity/window-api#get-shared-secrets) endpoint in the window API.

Once you get the shared secrets you can use them to encrypt/decrypt messages.

To help you code this flow, we made a [node.js code snippet](https://github.com/deso-protocol/examples/tree/main/identity/messages-shared-secret) in the examples repository which displays our messaging protocol.

## Webview Support

Identity also offers support for webview, but there are some differences needed in order to fully integrate.

Major differences:

* There is no need to run an iframe context. You will send all messages to one context running in a webview.
* Your webview context will need to have an additional parameter `?webview=true`
* Depending on your mobile development framework, you need to make sure messages to and from the webview are being registered appropriately. Currently iOS, Android, and React Native webviews are supported.


# Identity: iFrame API

Documentation on the iframe Context API

## Introduction

This guide describes the iframe API, which is an essential component of integrating with the DeSo Identity Service for web application developers.

If you haven't yet read through the [Identity: Overview](/deso-identity/identity) and [Core Concepts](/deso-identity/identity/concepts) guides, it would be helpful to do so prior to reading this documentation.

This guide also depends on [Identity: Window API](/deso-identity/window-api), so we recommend reading about it first.

The iframe API guide consists of two subpages, which should give you a comprehensive view of the API:

* [Overview](/deso-identity/iframe-api/basics) guide outlines the fundamentals of integrating with the iframe API
* [Endpoints](/deso-identity/iframe-api/endpoints) is an exhaustive list of all API endpoints.

If you're creating a mobile app, check out our [Mobile Integration](/deso-identity/identity/mobile-integration) guide next.


# Overview

Guide on integrating with the DeSo Identity iframe API

The iframe allows you to perform actions such as signing transactions or encrypting/decrypting messages without user interaction, as is the case in the [Identity: Window API](/deso-identity/window-api).

The iframe is usually entirely invisible to the user.

However, the iframe does need to render on some browsers such as Safari as the user needs to click on the iframe to grant it storage access.

We will explain how to implement this later in the guide.

In order to communicate with the iframe API, you need to include the iframe window HTML component into your app and point it to the `https://identity.deso.org/embed` URL.

Below is an example component.

We also provided you with an example with CSS styling.

```markup
<iframe
  id="identity"
  frameborder="0"
  src="https://identity.deso.org/embed"
  style="height: 100vh; width: 100vw; display: none; position: fixed; 
    z-index: 1000; left: 0; top: 0;"
></iframe>
```

Take notice of the CSS styling of the iframe component. As mentioned, the iframe is typically invisible to the user. That's why we set the `display: none` in the CSS style.

We also want the iframe window to be on top of your application and take the entire display, hence the other CSS attributes.

You should modify the `z-index` attribute to fit your application. In case that we will have to show the iframe to the user, you will set the attribute `display: block`

For example, `document.getElementById("identity.style.display = "block");`

## Messages

Communication with the iframe context is done through sending `postMessage()` requests. Similarly, the iframe context will send you responses by sending message events.

When you open the iframe context for the first time, the Identity will send you an `initialize` message, which requires you to respond.

This concept has been explained in more detail in the [Core Concepts](/deso-identity/identity/concepts#events) section.

When sending requests to the Identity iframe, you will need to include an `id` field. The `id` should be in [UUID v4](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_\(random\)) format.

We recommend using the [uuid npm package](https://www.npmjs.com/package/uuid), or you can also use the following implementation in Vanilla JavaScript:

```javascript
function uuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}
```

Here's an example message format that you can send to the Identity iframe.

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  method: 'info',
}
```

Let's take a look at what each of these fields mean:

* `id` should be generated to follow the UUID v4 format.
* `service` this should always be set to `"identity"` so that the DeSo Identity Service knows it's supposed to read this message.
* `method` this is the API type that you'll request, in this case it's `"info"` but it could be`"sign"`, `"encrypt"`, etc. as outlined in the [Identity: iFrame API](/deso-identity/iframe-api#api) section

You should index requests by `id` so that you can match them with responses.

We recommend looking at the [DeSo Protocol sourcecode](https://github.com/deso-protocol/frontend) to see how this could be implemented.&#x20;

In particular, you could trace through the `send()` method on [line #257 in `src/app/identity.service.ts`](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L257).

## Storage Access

Besides `initialize`, you will need to send an `info` message to the `iframe` context.

The DeSo Identity uses local storage and cookies to share information about users between the window and iframe contexts.

However, some browsers such as Safari and Chrome on iOS prevent storing data in such a way without user's explicit permission.

For example, Apple's Intelligent Tracking Prevention (ITP) places strict limitations on cross-domain data storage and access.

This means the Identity iframe must request storage access every time the page reloads.

This can be accomplished by showing the iframe to the user, i.e. setting `display: "block"`, and having the user click on the iframe.

When a user visits a DeSo application in Safari they will see a "Tap anywhere to unlock your wallet" prompt which is a giant button in the iframe. When the user clicks on the button, he will give Identity the required access.

Here's how it looks for the user:

![iframe UI for granting storage access](/files/q3k7wtOaomB70CgI7L2W)

To simplify this process, there's a special API call that you should perform, called `info`, that will indicate if you should display the iframe window to the user.

The best practice is to send the `info` message just when you're about to send the first non-`initialize` request (sign, encrypt, etc.) to the iframe API.

We recommend tracing through the `identity/iframe-info-storage-access` code snippet in the [examples repository,](https://github.com/deso-protocol/examples/tree/main/identity/iframe-info-storage-access/) which implements this communication pattern in Vanilla JavaScript using promises.

If you're familiar with [RxJS](https://rxjs.dev), you can also trace through the [Deso Protocol code](https://github.com/deso-protocol/frontend), starting with the `storageGranted` variable on [line #32](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/identity.service.ts#L32). Here's how the `info` request looks like:

#### Request

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  method: 'info',
}
```

And here's the response that the iframe will send you:

#### Response

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    browserSupported: true,
    hasCookieAccess: true,
    ​​hasLocalStorageAccess: true,
    ​​hasStorageAccess: true
  },
}
```

Let's take a look at the above payload fields:

* `browserSupported` tells you if DeSo Identity Service is compatible with the user's browser. If it's set to `false` you should notify the user that Identity won't work for them. Most modern browsers will output `true`.
* `hasCookieAccess` indicates if user browser allows cookies. Identity might store some information in cookies if local storage is unavailable.
* `hasLocalStorageAccess` will be `true` if local storage is available on user's browser.
* `hasStorageAccess` indicates if browser has access to storage. If it's set to `false` you will need to show the `iframe` window to the user so he can grant access. We will get to this next.

If the `info` message returns `hasStorageAccess: false`, your application should make the iframe take over the entire page.

You could do that by setting:

```javascript
document.getElementById("identity").style.display = "block"
```

The `info` message also detects if a user has disabled third party cookies.

Third party cookies are required for Identity to securely sign transactions.

If neither localStorage nor cookies are available, the `info` returns `browserSupported: false` and your application should inform the user they will not be able to use Identity to sign or decrypt anything.

When a user clicks "Tap anywhere to unlock your wallet," the iframe will indicate it by sending a `storageGranted` message.&#x20;

This request does not expect a response. When your application receives the `storageGranted` message it can hide the `iframe` window from the user and the iframe is now ready to receive `sign` and `decrypt`, etc. messages.

To hide the `iframe`, simply call:

```javascript
document.getElementById("identity").style.display = "none"
```

#### `storageGranted` Message

```javascript
{
  service: 'identity',
  method: 'storageGranted',
}
```

## User Credentials

In order to use the iframe API, you will need to first acquire secure user credentials from the [Identity: Window API](/deso-identity/window-api), through the [Identity: Window API](/deso-identity/window-api#log-in) endpoint.

The user credentials include three fields, namely `encryptedSeedHex,` `accessLevel`, and`accessLevelHmac`.

Which you have to include in all requests to the iframe API. We also explained this concept in the [Core Concepts](/deso-identity/identity/concepts#accounts) section.


# Endpoints

List of DeSo Identity iframe API endpoints

#### Note:

The iframe API supports functionality for both public keys and derived keys. You can determine key type from the login response by checking for `derivedPublicKeyBase58Check`.

## sign

[**AccessLevel**](broken://pages/-MjtsPMUQ3Cy0qFbx04f#access-levels)**: 3, 4 (depends on** [**transaction**](https://github.com/deso-protocol/identity/blob/9dad527dc46498b9aaa0344abd70dc8895acf246/src/app/identity.service.ts#L288)**)**

The sign message is responsible for signing transaction hexes. If approval is required an application must call the [Identity: Window API](/deso-identity/window-api#approve) endpoint in the Window API to sign the transaction.

#### Payload for public keys

<table><thead><tr><th width="295.3333333333333">Name</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>transactionHex</td><td>string</td><td>Hex of the transaction you want to sign.</td></tr></tbody></table>

#### Payload for derived keys

| Name                        | Type   | Description                                                                                      |
| --------------------------- | ------ | ------------------------------------------------------------------------------------------------ |
| transactionHex              | string | Hex of the transaction you want to sign.                                                         |
| derivedPublicKeyBase58Check | string | Only required if logged in user is using a derived key to sign on behalf of an owner public key. |

#### Request

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  method: 'sign',
  payload: {
    accessLevel: 4,
    accessLevelHmac: "0fab13f4...",
    encryptedSeedHex: "0fab13f4...",
    transactionHex: "0fab13f4...",
    derivedPublicKeyBase58Check: "0fab13f4...",

  },
}
```

#### Response (Success)

You will get this response if the transaction was successful signed.

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    signedTransactionHex: "0fab13f4...",
  },
}
```

#### Response (Approval Required)

You will get this response if the `accessLevel` your user has authorized doesn't match the access level required to sign a transaction.

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    approvalRequired: true,
  },
}
```

## encrypt

[**AccessLevel**](broken://pages/-MjtsPMUQ3Cy0qFbx04f#access-levels)**: 2**

The encrypt API is responsible for encrypting messages. For more details check out [Core Concepts](/deso-identity/identity/concepts#messages)

#### Payload for public keys

<table><thead><tr><th width="316.3333333333333">Name</th><th width="127">Type</th><th>Description</th></tr></thead><tbody><tr><td>recipientPublicKey</td><td>string</td><td>Public key of the recipient in base58check format.</td></tr><tr><td>message</td><td>string</td><td>Message text that you want to encrypt.</td></tr></tbody></table>

#### Payload for derived keys

Only required if logged in user is using a derived key to sign on behalf of an owner public key.

<table><thead><tr><th width="322"></th><th width="120"></th><th></th></tr></thead><tbody><tr><td>recipientPublicKey</td><td>string</td><td>Public key of the recipient in base58check format.</td></tr><tr><td>message</td><td>string</td><td>Message text that you want to encrypt.</td></tr><tr><td>encryptedMessagingKeyRandomness</td><td>string</td><td>This value is used in place of the <code>encryptedSeedHex</code> when encrypting the message.</td></tr><tr><td>derivedPublicKeyBase58Check</td><td>string</td><td>Public key requesting encryption in base58check format.</td></tr><tr><td>ownerPublicKeyBase58Check</td><td>string</td><td>Public key used  only for validation. </td></tr></tbody></table>

#### Request

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  method: 'encrypt',
  payload: {
    accessLevel: 3,
    accessLevelHmac: "0fab13f4...",
    encryptedSeedHex: "0fab13f4...",
    recipientPublicKey: "BC1YLgwkd7iADbrSgryTfXhMEcsF76cXDaWog4aDzoTunDb2DcZ3myZ"
    message: "This is a message",
    derivedPublicKeyBase58Check: "BC1YLsond7iADbrSgryTfXhMEcsF76cXDaWog4aDzoTunDb2DcZ3myZ",
    ownerPublicKeyBase58Check: "BC1YLdadd7iADbrSgryTfXhMEcsF76cXDaWog4aDzoTunDb2DcZ3myZ",
    encryptedMessagingKeyRandomness: "837fab39...",
    
  },
}
```

#### Response for Derived keys (Encrypted Messaging Key Randomness Required)

You will get this response if the request includes a `derivedPublicKeyBase58Check` and does not include both `ownerPublicKeyBase58Check` and `encryptedMessagingKeyRandomness`.

```javascript
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    encryptedMessage: "",
    requiresEncryptedMessagingKeyRandomness: true,
  },
}
```

You can request Encrypted MessagingKeyRandomness by calling the messaging-group in the Window API.

#### Response (Approval Required)

You will get this response if the `accessLevel` your user has authorized doesn't match the access level required to sign a transaction.

To fix, the user needs to allow at least access level 2.

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    approvalRequired: true,
  },
}
```

#### Response

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    encryptedMessage: "0fab13f4...",
  },
}
```

## decrypt

[**AccessLevel**](broken://pages/-MjtsPMUQ3Cy0qFbx04f#access-levels)**: 2**

The decrypt API is responsible for decrypting messages.

As we mentioned in the [Core Concepts](/deso-identity/identity/concepts#messages) section, the current messaging protocol is `V2`; however, it is still possible to decrypt messages from the `V1` scheme.

The decrypt API allows you to decrypt multiple messages at once by passing an array of `encryptedMessage` objects.

The `decrypt` API is intended to be constructed right after calling the `/api/v0/get-messages-stateless` backend API endpoint, and so the structure of `encryptedMessage` matches the structure of the response from backend.

We recommend tracing through [`GetMessages()` ](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/backend-api.service.ts#L1293)function in the DeSo Protocol frontend's `src/app/backend-api.service.ts`.

Assuming `message` is a taken from `OrderedContactsWithMessages.Messages` from the backend API response, `encryptedMessage` can be constructed as follows:

```javascript
encryptedMessage : {
    EncryptedHex: message.EncryptedText,
    PublicKey: message.IsSender ? message.RecipientPublicKeyBase58Check : message.SenderPublicKeyBase58Check,
    IsSender: message.IsSender,
    Legacy: !message.V2,
}
```

Another use-case for the `decrypt` API is decrypting unlock-able text in NFTs.

To see how this can be done, we recommend tracing through the [`DecryptUnlockableTexts()`](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/backend-api.service.ts#L945) in the DeSo Protocol repository.

#### Payload for public keys

| Name              | Type                | Description                         |
| ----------------- | ------------------- | ----------------------------------- |
| encryptedMessages | \[]encryptedMessage | List of encrypted messages objects. |

#### Payload for derived keys

<table><thead><tr><th></th><th width="201"></th><th></th></tr></thead><tbody><tr><td>derivedPublicKeyBase58Check</td><td>string</td><td>Public key requesting decryption in base58check format.</td></tr><tr><td>ownerPublicKeyBase58Check</td><td>string</td><td>Used to identify which messaging group member entry is used to decrypt group messages.</td></tr><tr><td>encryptedMessagingKeyRandomness</td><td>string</td><td>Required to decrypt the request.</td></tr><tr><td>encryptedMessages</td><td>[]encryptedMessage</td><td>List of encrypted messages objects.</td></tr></tbody></table>

#### Request

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  method: 'decrypt',
  payload: {
    accessLevel: 3,
    accessLevelHmac: "0fab13f4...",
    encryptedSeedHex: "0fab13f4...",
    derivedPublicKeyBase58Check: "BC1YLsond7iADbrSgryTfXhMEcsF76cXDaWog4aDzoTunDb2DcZ3myZ",
    ownerPublicKeyBase58Check: "BC1YLdadd7iADbrSgryTfXhMEcsF76cXDaWog4aDzoTunDb2DcZ3myZ",
    encryptedMessagingKeyRandomness: "837fab39...",
    encryptedMessage: [
      {
        EncryptedHex: "0f154bcad...",
        PublicKey: "BC1a4gbK1...",
        IsSender: true,
        Legacy: false
      },
      {
        EncryptedHex: "0afa44bcd...",
        PublicKey: "BC1asKl5j1...",
        IsSender: false,
        Legacy: true
      }, ...
    ]
  },
}
```

#### Response (Encrypted Messaging Key Randomness Required)

You will get this response if the request includes a `derivedPublicKeyBase58Check` and does not include both `ownerPublicKeyBase58Check` and `encryptedMessagingKeyRandomness`.

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    decryptedHexes: {}
    requiresEncryptedMessagingKeyRandomness: true,
  },
}
```

#### Response (Approval Required)

You will get this response if the `accessLevel` your user has authorized doesn't match the access level required to sign a transaction.

To fix, the user needs to allow at least access level 2.

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    approvalRequired: true,
  },
}
```

#### Response

Response contains a `decryptedHexes` field which is a map of decrypted messages, indexed by `EncryptedHex` from the request.

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    decryptedHexes: {
      "0f154bcad...": "hello world"
      "0afa44bcd...": "in retrospect it was inevitable",
    }
  },
}
```

## jwt

[**AccessLevel**](broken://pages/-MjtsPMUQ3Cy0qFbx04f#access-levels)**: 2**

The `jwt` message creates signed JWT tokens that can be used to verify a user's ownership of a specific public key.

The JWT is only valid for 10 minutes.

JWTs are used in some Backend API endpoints such as `/api/v0/upload-image.` The best practice is to request the JWT right before calling these endpoints.

#### Payload for public keys

| Name | Type | Description |
| ---- | ---- | ----------- |
| N/A  | N/A  | No payload. |

#### payload for derived keys

<table><thead><tr><th width="348">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>derivedPublicKeyBase58Check</td><td>string </td><td>Informs Identity on how to sign the transaction.</td></tr></tbody></table>

#### Request

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  method: 'jwt',
  payload: {
    accessLevel: 3,
    accessLevelHmac: "0fab13f4...",
    encryptedSeedHex: "0fab13f4...",
    derivedPublicKeyBase58Check: "BC1YLsond7iADbrSgryTfXhMEcsF76cXDaWog4aDzoTunDb2DcZ3myZ",
  },
}
```

#### Response

```javascript
{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    jwt: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2MTk2NDk4MDcsImV4cCI6MTYxOTY0OTg2N30.FKZF8DSwwlnUaW_eRa7Wr1v2QcG7_iDN-NjdqXUcgrSAPg1EdSfpWsLL4GeUiD9zdLUgrNoKU7EsKkE-ZKMaVQ",
  },
}
```

#### Validation in Go

In case you want to validate the JWT token in Go, you could use the code below:

```javascript
func (fes *APIServer) ValidateJWT(publicKey string, jwtToken string) (bool, error) {
	pubKeyBytes, _, err := lib.Base58CheckDecode(publicKey)
	if err != nil {
		return false, errors.Wrapf(err, "Problem decoding public key")
	}

	pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256())
	if err != nil {
		return false, errors.Wrapf(err, "Problem parsing public key")
	}

	token, err := jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) {
		// Do not check token issued at time. We still check expiration time.
		mapClaims := token.Claims.(jwt.MapClaims)
		delete(mapClaims, "iat")

		// We accept JWT signed by derived keys. To accommodate this, the JWT claims payload should contain the key
		// "derivedPublicKeyBase58Check" with the derived public key in base58 as value.
		if derivedPublicKeyBase58Check, isDerived := mapClaims[JwtDerivedPublicKeyClaim]; isDerived {
			// Parse the derived public key.
			derivedPublicKeyBytes, _, err := lib.Base58CheckDecode(derivedPublicKeyBase58Check.(string))
			if err != nil {
				return nil, errors.Wrapf(err, "Problem decoding derived public key")
			}
			derivedPublicKey, err := btcec.ParsePubKey(derivedPublicKeyBytes, btcec.S256())
			if err != nil {
				return nil, errors.Wrapf(err, "Problem parsing derived public key bytes")
			}
			// Validate the derived public key.
			utxoView, err := fes.mempool.GetAugmentedUniversalView()
			if err != nil {
				return nil, errors.Wrapf(err, "Problem getting utxoView")
			}
			blockHeight := uint64(fes.blockchain.BlockTip().Height)
			if err := utxoView.ValidateDerivedKey(pubKeyBytes, derivedPublicKeyBytes, blockHeight); err != nil {
				return nil, errors.Wrapf(err, "Derived key is not authorize")
			}

			return derivedPublicKey.ToECDSA(), nil
		}

		return pubKey.ToECDSA(), nil
	})

	if err != nil {
		return false, errors.Wrapf(err, "Problem verifying JWT token")
	}

	return token.Valid, nil
}
```


# Identity: Window API

Documentation on the Window Context API

## Introduction

This guide describes the Window API, which is an essential component of integrating with the DeSo Identity Service.

If you haven't yet read through the [Identity: Overview](/deso-identity/identity) and [Core Concepts](/deso-identity/identity/concepts) guides, it would be helpful to do so prior to reading this documentation.

The Window API guide consists of two subpages, which should give you a comprehensive view of the API:

* [Overview](/deso-identity/window-api/basics) guide outlines the fundamentals of integrating with the Window API
* [Endpoints](/deso-identity/window-api/endpoints) is an exhaustive list of all API endpoints.

Upon finishing reading about the Window API, we recommend taking a look at the [Identity: iFrame API](/deso-identity/iframe-api), especially if you're developing a web application.

And if you're creating a mobile app, check out our [Mobile Integration](/deso-identity/identity/mobile-integration) guide next.


# Overview

Guide on integrating with the DeSo Identity Window API

In this guide, we will explain how to integrate the DeSo Identity window API into your application.&#x20;

When developing applications that handle user authentication, there are always some actions that require user interaction.

In traditional Web2 applications, this often involves the user having to type information such as username and password, or the user clicking on a third-party login such as Google or Apple.

On the other hand, decentralized Web3 applications are powered by blockchains and consequently, they rely on public and private keys.

The underlying mathematics of blockchains can often appear complicated, both for the user and for the developer.

To solve these issues, we designed the DeSo Identity Service which hides the cryptographic complexities of user authentication underneath a simple window API.

With DeSo Identity Service you don't need to worry about implementing any HTML forms or input validation, you just need to make correct calls to the window API.

The window API is responsible for opening Identity either as a pop-up window or as a new tab. Opening Identity in a window context is as simple as launching a `window.open`.&#x20;

Here are examples of some calls that can be made to Identity:

```javascript
const login   = window.open('https://identity.deso.org/log-in');
const signUp  = window.open('https://identity.deso.org/sign-up');
const logout  = window.open('https://identity.deso.org/logout?publicKey=BC123...');
const approve = window.open('https://identity.deso.org/approve?tx=0abf35a...');

// Can be added to any path for testnet deso and bitcoin addresses
const testnet = window.open('https://identity.deso.org/log-in?testnet=true');
```

And here's an example user interface after launching the `log-in` endpoint with a couple of URL parameters, in this case, `accessLevelRequest=4`&#x20;

You might remember the `accessLevelRequest` URL parameter from the [Core Concepts](/deso-identity/identity/concepts#access-levels) section in our Introduction guide.

There are other URL parameters that you can use and we will explain them in this document.

![Example usage of Window API](/files/CwANHZv36cRJOHuK0nFb)

Once the window context is launched, the user has to perform an action, such as login or signup.&#x20;

After the user completes the flow, your app will receive either a `postMessage` or a `callback` containing secure user credentials and payload of the desired API endpoint.

You can then use the user credentials for communicating with the [Identity: iFrame API](/deso-identity/iframe-api). We recommend the following format for opening the Identity window context:

```javascript
// center the window.
const h = 1000;
const w = 800;
const y = window.outerHeight / 2 + window.screenY - h / 2;
const x = window.outerWidth / 2 + window.screenX - w / 2;
const win = window.open("https://identity.deso.org/log-in", null, `toolbar=no, width=${w}, height=${h}, top=${y}, left=${x}`);
```

When we pass the public key to the Identity window API, it should always be in **base58check** format:

```javascript
BC1YLgwkd7iADbrSgryTfXhMEcsF76cXDaWog4aDzoTunDb2DcZ3myZ
```

**Note:** <mark style="color:red;">Only one Identity window should be opened at a time.</mark>

## Messages

Normally, the DeSo Identity Service will communicate with your application via [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).

In order to listen to these messages, you have to declare an event handler in the parent window context, as shown below.

The first message sent by Identity is `method: "initialize"`, and your application has to send a response.

We explained this mechanism in more detail in our [Core Concepts](/deso-identity/identity/concepts#events) and [Core Concepts](/deso-identity/identity/concepts#initialize) guides.

```javascript
window.addEventListener("message", (event) => this.handleMessage(event));
```

When the user completes an action within the window context, Identity will send a `postMessage` to your application containing the payload corresponding to the launched endpoint.

These messages will usually contain a `method: "login"` field so that it's easier to handle closing the identity window as described in the [Identity: Window API](/deso-identity/window-api#termination) section.

However, some endpoints will contain a different method, such as the [Identity: Window API](/deso-identity/window-api#derive) endpoint.&#x20;

Messages sent by the window API will also include an `id: null` field, which indicates that they do not require a response from your application.

Below is an example `event.data` response from the `log-in` endpoint.

```javascript
{
  id: null,
  service: "identity",
  method: "login",
  payload: {
    users: {
      BC1YLj8iwsicimv8ttrPg6rBtizvM7X3KCsiVQwYZKqj6Wj3rT8TD3D: {
        hasExtraText: false,
        btcDepositAddress: "16YqLEpYzeV1aCcp7YwHKh9m5Kg4Sd8eak",
        ethDepositAddress: "0xf8212f8d8E881090653bFF0AC99f499063bCFE77",
        version: 1,
        encryptedSeedHex: "0ac1d9e14c640a26ea3f70095f9b27a50ef06652aea7a2f19f086d750e5f4ecf2d752568b9e3fd3400ad8581d9cf8da5dab3ea29078c1a528f81a51b55514ed5",
        network: "mainnet",
        accessLevel: 4,
        accessLevelHmac: "d66741dcf7a828e7b2b3c44708643de335de28b7a4941eeb687a6d5b1da66e77"
      }
    },
    publicKeyAdded: "BC1YLj8iwsicimv8ttrPg6rBtizvM7X3KCsiVQwYZKqj6Wj3rT8TD3D",
    signedUp: true
  }
}
```

Most responses from the window context will have the same structure as above.

A typical response will contain the `users` object, which reflects all users that have previously logged in to your application.

The `users` object is a map of `publicKey => userCredentials` where the credentials are used primarily for communicating with the `iframe` context.

In such requests, we will be passing the `encryptedSeedHex, accessLevel, accessLevelHmac` which are used by DeSo Identity to ensure that the user has been securely authenticated via the window context.

User credentials should be saved in local storage.

You should always overwrite existing credentials whenever you receive a `method: "login"` response.

This is because some requests can cause Identity to reauthorize all users and their credentials like `encryptedSeedHex` will change.

In the DeSo Protocol implementation, we do this via `this.backend.setIdentityServiceUsers()` on [line #857](https://github.com/deso-protocol/frontend/blob/6d6225a8425f2fe7ad84a222027159333b2c754f/src/app/global-vars.service.ts#L857) in `/src/app/global-vars.service.ts` which uses the [`localStorage` API](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to store data.

If you're unfamiliar with `localStorage`, below are the three main API calls you'll need.

In the reference implementation, we simply store the entire `payload.users` field under a single key called `IdentityUsersKey = "identityUsersV2"`

```javascript
// Store data in localStorage with (key, value) = (IdentityUsersKey, users)
// We assume the users value is a JSON object so:
localStorage.setItem(IdentityUsersKey, JSON.stringify(userCredentials));

// Read data from localStorage at publicKey
const users = JSON.parse(localStorage.getItem(IdentityUsersKey));

// Remove data from localStorage at publicKey
localStorage.removeItem(IdentityUsersKey);
```

Apart from the `users` field, the response will contain fields that are specific to the requested API endpoint.

When we called the `log-in` endpoint, the response also contained `publicKeyAdded` of the logged user and `signedUp` indicating that the user has signed up.

More information on these fields can be found in the [Identity: Window API](/deso-identity/window-api#endpoints) section.

## Callbacks

If you're building a mobile application, you most likely want to be using callbacks instead of messages.

Launching the window context with a `callback` URL causes the Identity window to send the payload via URL parameters rather than a `postMessage`.

The callback mechanism works similarly to how OAuth is typically implemented in mobile apps.&#x20;

Callbacks are intended to be used in combination with derived keys so they currently work for [Identity: Window API](/deso-identity/window-api#derive) and [Identity: Window API](/deso-identity/window-api#get-shared-secrets) endpoints.

Because responses to these endpoints contain sensitive user information, the provided **`callback`** **URL should always be a local address**.

Below is an example call to the `derive` endpoint with a `auth://derive` callback URL:

```javascript
const derive = window.open('https://identity.deso.org/derive?callback=auth://derive');
```

After user finishes the Identity flow the payload will be sent via URL parameters as a GET request to the provided callback like this:

```javascript
GET auth://derive?param1=value1&param2=value2&...
```

Where the `param1=value1` , `param2=value2` fields will match the structure of the response payload of to the `/derive` endpoint as explained in the [Identity: Window API](/deso-identity/window-api#derive) section.

## Termination

When a user finishes any action in an Identity window, a `method: "login"` message is sent or a `callback` is called.

After you receive the payload from your desired API endpoint, you should close the Identity window by calling `window.close()` on the window object.

When the Identity window is open, you can also communicate with it just like you would with the `iframe` API. This is sometimes useful if you want to sign a transaction or generate a JWT.


# Endpoints

List of DeSo Identity Window API endpoints

This section describes all endpoints for the Window API.

Endpoints are called with URL parameters, some of which are optional. After the user completes the flow within the window, Identity will send a `postMessage` response.

## log-in

This endpoint is used to handle user login or account creation.

#### Request

```javascript
const login = window.open('https://identity.deso.org/log-in');
```

#### URL Parameters

| Name                          | Type   | Description                                                                                                                                                                                                                  |
| ----------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| accessLevelRequest (optional) | int    | Requested access level, as in [Core Concepts](/deso-identity/identity/concepts#access-levels) Default is Access Level 2                                                                                                      |
| testnet (optional)            | bool   | Whether we're on testnet or mainnet. Default is `false`                                                                                                                                                                      |
| webview (optional)            | bool   | Whether we're using webview. Default is `false`                                                                                                                                                                              |
| jumio (optional)              | bool   | Whether to show "get free deso" during signup. Default is `false`                                                                                                                                                            |
| referralCode (optional)       | string | Referral Code through which the user accessed the site. The referral code allows the user to get a greater amount of money as a sign-up bonus. Also check out[Identity: Window API](/deso-identity/window-api#get-free-deso) |
| hideGoogle (optional)         | bool   | Hide Google login from the Identity UI. Default is `false`                                                                                                                                                                   |

`accessLevelRequest` can take values from {0, 2, 3, 4}. You should only ask for the lowest permission that fits the requirements of your application.

Here's what each level means:

```javascript
enum AccessLevel {
  // User revoked permissions
  None = 0,

  // Approval required for all transactions.
  // This means no account action is authorized.
  ApproveAll = 2, /* DEFAULT */

  // Approval required for buys, sends, and sells
  // This authorizes all non-spending actions.
  ApproveLarge = 3,

  // Node can sign all transactions without approval
  // This authorizes all non-spending & spending actions.
  Full = 4,
}
```

#### Response

```javascript
{
  id: null,
  service: "identity",
  method: "login",
  payload: {
    users: {
      BC1YLfsWMfv8UdytwrWqWvqSP6M6eQJg7W5TWL1WNDYd7zxi6wEShQX: {
        accessLevel: 4,
        accessLevelHmac: "0d22e283751c904ab36dc3910afe1a981...",
        btcDepositAddress: "1PXhm3D6sgZtfGNe2mtP27NVBHEcNJX2AW",
        encryptedSeedHex: "bdad93a19eb3be8b4c2f63b5cefb82823...",
        hasExtraText: false,
        network: "mainnet",
      },
      BC1...
    },
    publicKeyAdded: 'BC1YLfsWMfv8UdytwrWqWvqSP6M6eQJg7W5TWL1WNDYd7zxi6wEShQX',
    signedUp: false,
  }
}
```

For a log in or sign up action, the selected `publicKey` will be included in `publicKeyAdded`.&#x20;

When a user signs up the `signedUp` field will be set to `true`, otherwise it'll be `false` for log in.

An application should store the current `publicKeyAdded` and `users` objects in its local storage.

You should always overwrite the existing, saved users.

Check out the [Identity: Window API](/deso-identity/window-api#messages) section for more information.

When an application wants to sign a transaction or decrypt a message, the `accessLevel`, `accessLevelHmac`, and `encryptedSeedHex` values will be required.

## logout

Logout is used to reset the `accessLevel` of an individual user. You should handle user logout by calling this endpoint.

When you logout a user, you should delete the corresponding `userCredentials` entry form the local storage/database.

Consult the [Identity: Window API](/deso-identity/window-api#messages) section for more information.

#### Request

```javascript
const logout = window.open('https://identity.deso.org/logout');
```

#### URL Parameters

| Name               | Type   | Description                                             |
| ------------------ | ------ | ------------------------------------------------------- |
| publicKey          | string | Public key of the user that is logging out              |
| testnet (optional) | bool   | Whether we're on testnet or mainnet. Default is `false` |
| webview (optional) | bool   | Whether we're using webview. Default is `false`         |

#### Response

```javascript
{
  id: null,
  service: "identity",
  method: "login",
  payload: {
    users: {
      BC1YLfsWMfv8UdytwrWqWvqSP6M6eQJg7W5TWL1WNDYd7zxi6wEShQX: {
        accessLevel: 4,
        accessLevelHmac: "0d22e283751c904ab36dc3910afe1a981...",
        btcDepositAddress: "1PXhm3D6sgZtfGNe2mtP27NVBHEcNJX2AW",
        encryptedSeedHex: "bdad93a19eb3be8b4c2f63b5cefb82823...",
        hasExtraText: false,
        network: "mainnet",
      },
      BC1...
    }
  }
}
```

## approve

The approve endpoint is used for transaction signing.

If you're unsure what this means, make sure to check out the [Core Concepts](/deso-identity/identity/concepts#transactions) section to see how transactions work in the DeSo blockchain.&#x20;

Usually, the approve endpoint is called when you want to sign a transaction that's outside the scope of the [`accessLevel`](broken://pages/-MjtsPMUQ3Cy0qFbx04f#access-levels) you have requested during [Identity: Window API](/deso-identity/window-api#log-in).

For example, if you requested `accessLevel=3` and want to sign a `BasicTransfer` transaction (constructed via `api/v0/send-deso`Backend API), you would need to use the approve endpoint because `BasicTransfer` requires `accessLevel=4`.

If the transaction you want to sign is within the scope of the `accessLevel` you have, you should sign it through the [Identity: iFrame API](/deso-identity/iframe-api).

#### Request

```javascript
const approve = window.open('https://identity.deso.org/approve');
```

#### URL Parameters

| Name               | Type   | Description                                             |
| ------------------ | ------ | ------------------------------------------------------- |
| tx                 | string | Transaction hex of the transaction to sign              |
| testnet (optional) | bool   | Whether we're on testnet or mainnet. Default is `false` |
| webview (optional) | bool   | Whether we're using webview. Default is `false`         |

#### Response

```javascript
{
  id: null,
  service: "identity",
  method: "login",
  payload: {
    users: {
      BC1YLfsWMfv8UdytwrWqWvqSP6M6eQJg7W5TWL1WNDYd7zxi6wEShQX: {
        accessLevel: 4,
        accessLevelHmac: "0d22e283751c904ab36dc3910afe1a981...",
        btcDepositAddress: "1PXhm3D6sgZtfGNe2mtP27NVBHEcNJX2AW",
        encryptedSeedHex: "bdad93a19eb3be8b4c2f63b5cefb82823...",
        hasExtraText: false,
        network: "mainnet",
      },
      BC1...
    },
    signedTransactionHex: "0196be9786f1634b2734196bad0798..."
  }
}
```

## derive

The derive endpoint is used to generate a derived key for a user.

When you hold a derived key, you can sign transactions for a user without having to interact with the DeSo Identity Service.

Derived keys are intended to be used primarily in mobile applications and with [Identity: Window API](/deso-identity/window-api#callbacks).

If no callback is specified, you will receive the derived key through [Identity: Window API](/deso-identity/window-api#messages).

In such case, you will receive the payload with `method: "derive"` (opposed to `"login"`). More information on derived keys can be found in [Mobile Integration](/deso-identity/identity/mobile-integration#derived-keys).

After the Transaction Spending Limits fork height hits, derived keys will require authorization of transaction spending limits, which provides granular permissions on transaction type and even more granular permissions on NFTs, Creator Coins, and DAO Coins.

To learn more, read the [Mobile Integration](/deso-identity/identity/mobile-integration#derived-keys) section.

#### Request

```javascript
const derive = window.open('https://identity.deso.org/derive');
```

#### URL Parameters

<table><thead><tr><th width="265">Name</th><th width="150">Type</th><th>Description</th></tr></thead><tbody><tr><td>callback (optional)</td><td>string</td><td>Callback URL for the payload as explained in <a data-mention href="/pages/PWMt3tz9E8T1xCTaDlyf#callbacks">/pages/PWMt3tz9E8T1xCTaDlyf#callbacks</a></td></tr><tr><td>testnet (optional)</td><td>bool</td><td>Whether we're on testnet or mainnet. Default is <code>false</code></td></tr><tr><td>webview (optional)</td><td>bool</td><td>Whether we're using webview. Default is <code>false</code></td></tr><tr><td>TransactionSpendingLimit</td><td>string</td><td><a data-mention href="/pages/pK92RdbTZJy2NdpI52Cc#transactionspendinglimitresponse">/pages/pK92RdbTZJy2NdpI52Cc#transactionspendinglimitresponse</a> as a JSON string. Use <code>encodeURIComponent(JSON.stringify(transactionSpendingLimitResponse))</code></td></tr><tr><td>PublicKey</td><td>String</td><td>Public key (in base 58) for which you want to generate a derived key (Optional)</td></tr><tr><td>DerivedPublicKey</td><td>String</td><td>Derived key (in base 58) that you want to use instead of allowing identity to generate a new one (Optional)</td></tr></tbody></table>

#### Response

```javascript
{
  id: null,
  service: "identity",
  method: "derive",
  payload: {
    derivedSeedHex: "40538066039f21f42f0247f49fe4e7d63a9d80528486b02fea37ce3c57886546",
    derivedPublicKeyBase58Check: "BC1YLjGYUcpF7HMqmUYNoDaV7Wxc8TYoGhGwmigyEVSCKNAxU9GmikD",
    publicKeyBase58Check: "BC1YLj8iwsicimv8ttrPg6rBtizvM7X3KCsiVQwYZKqj6Wj3rT8TD3D",
    btcDepositAddress: "Not implemented yet",
    ethDepositAddress: "Not implemented yet",
    expirationBlock: 91587,
    network: "mainnet",
    accessSignature: "304502206a612483e970e3494191e5242683b2be8d22ca6e20473e990f50098021099d8b022100f5b011ea683499dee50079ed2497bfbd16461e802e53f956d4c9c6cdaa423f47",
    jwt: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2Mzc5OTQ3NDMsImV4cCI6MTY0MDU4Njc0M30.o74505dYS0qZ5EqSxeYiuSzMCTFRLEToLXmudTtbdk3oYhu80M95qbHX5BjHQw4Bvuh7yz8Hv1u2-leReAaf9Q",
    derivedJwt: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2Mzc5OTQ3NDMsImV4cCI6MTY0MDU4Njc0M30.Nb1IuWgOxrG21NG6zyHMA6M-Mlq2kVrIPVNWAhj49jlaDCqlGQAAEBOl4jlVBC3vNU0S9yyq_8QI5Gmz4Qk1lA"
  }
}
```

The meaning of each of these fields is explained in [Mobile Integration](/deso-identity/identity/mobile-integration#derived-keys). In the case of the callback, all these fields will be passed as URL parameters.

Assuming, we've passed `callback=auth://derive`, the payload will be sent as a GET request like this:

```javascript
GET auth://derive?derivedSeedHex=...&derivedPublicKey=...&publicKey=...&
btcDepositAddress=...&ethDepositAddress=...&expirationBlock=...&network=...&
accessSignature=...&jwt=...&derivedJwt=...
```

## get-shared-secrets

This endpoint is intended to be used in combination with derived keys.

It allows you to get message encryption/decryption keys, or shared secrets, so that you can read messages without querying Identity (as is traditionally done via [Identity: iFrame API](/deso-identity/iframe-api)).

The `get-shared-secrets` endpoint requires a callback as well as other URL parameters that are used to verify ownership of the derived key.

Another required URL parameter is `messagePublicKeys` which are the public keys of messaging parties in [CSV format](https://en.wikipedia.org/wiki/Comma-separated_values#Basic_rules) for which we want to fetch shared secrets.

The `get-shared-secrets` endpoint allows to fetch multiple shared secrets at once.

For example, if the owner of the derived key was public key `A`, and we wanted to read conversations between parties `B`,`C`,`D` (or more) we would set `ownerPublicKey=A` and `messagePublicKeys=B,C,D` .

#### Request

```javascript
const secrets = window.open('https://identity.deso.org/get-shared-secrets');
```

#### URL Parameters

| Name               | Type                                                                                    | Description                                                                                              |
| ------------------ | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| callback           | string                                                                                  | Callback URL for the payload as explained in [Identity: Window API](/deso-identity/window-api#callbacks) |
| ownerPublicKey     | string                                                                                  | Master public key that was used to get the derived key                                                   |
| derivedPublicKey   | string                                                                                  | Derived public key                                                                                       |
| JWT                | string                                                                                  | JWT signed by the derived key, it's passed as `derivedJwt` in `/derive`                                  |
| messagePublicKeys  | strings, [CSV format](https://en.wikipedia.org/wiki/Comma-separated_values#Basic_rules) | Public keys of users for which we want to fetch shared secrets.                                          |
| testnet (optional) | bool                                                                                    | Whether we're on testnet or mainnet. Default is `false`                                                  |

#### Response

The response is a list of shared secrets in CSV format corresponding to `messagePublicKeys` . The payload will always be sent as a [Identity: Window API](/deso-identity/window-api#callbacks).

```javascript
GET callback?sharedSecrets=ccf9474d7578658e0c77adb7aea5cc9b61d3bccad5bddddd11e1850dfa4db059,
    db7aea5cc9b61d3b..., a11e1850dfa4db059...
```

## get-free-deso

The `get-free-deso` endpoint allows for launching the Jumio KYC flow, and if completed successfully, it will end up sending your users free starter DeSo or their referral bonus.

#### Request

```javascript
const free = window.open('https://identity.deso.org/get-free-deso');
```

#### URL Parameters

| Name                    | Type   | Description                                             |
| ----------------------- | ------ | ------------------------------------------------------- |
| public\_key             | string | Public key of the user to be KYC verified               |
| referralCode (optional) | string | Referral code to be used in Jumio                       |
| testnet (optional)      | bool   | Whether we're on testnet or mainnet. Default is `false` |

#### Response

```javascript
{
  id: null,
  service: "identity",
  method: "login",
  payload: {
    users: {
      BC1YLfsWMfv8UdytwrWqWvqSP6M6eQJg7W5TWL1WNDYd7zxi6wEShQX: {
        accessLevel: 4,
        accessLevelHmac: "0d22e283751c904ab36dc3910afe1a981...",
        btcDepositAddress: "1PXhm3D6sgZtfGNe2mtP27NVBHEcNJX2AW",
        encryptedSeedHex: "bdad93a19eb3be8b4c2f63b5cefb82823...",
        hasExtraText: false,
        network: "mainnet",
      },
      BC1...
    },
    publicKeyAdded: "BC1...",
    signedUp: true,
    jumioSuccess: true
  }
}
```

The `signedUp` boolean variable determines if the user has logged in or signed up, and `jumioSuccess` indicates if the Jumio KYC was successful.

## verify-phone-number

The `verify-phone-number` endpoint will give the user some starter DeSo after a successful phone verification.

#### Request

```javascript
const phone = window.open('https://identity.deso.org/verify-phone-number');
```

#### URL Parameters

| Name               | Type   | Description                                             |
| ------------------ | ------ | ------------------------------------------------------- |
| public\_key        | string | Public key of the user to be phone verified             |
| testnet (optional) | bool   | Whether we're on testnet or mainnet. Default is `false` |

#### Response

```javascript
{
  id: null,
  service: "identity",
  method: "login",
  payload: {
    users: {
      BC1YLfsWMfv8UdytwrWqWvqSP6M6eQJg7W5TWL1WNDYd7zxi6wEShQX: {
        accessLevel: 4,
        accessLevelHmac: "0d22e283751c904ab36dc3910afe1a981...",
        btcDepositAddress: "1PXhm3D6sgZtfGNe2mtP27NVBHEcNJX2AW",
        encryptedSeedHex: "bdad93a19eb3be8b4c2f63b5cefb82823...",
        hasExtraText: false,
        network: "mainnet",
      },
      BC1...
    },
    publicKeyAdded: "BC1...",
    signedUp: true,
    phoneNumberSuccess: true
  }
}
```

The `signedUp` boolean variable determines if the user has logged in or signed up, and `phoneNumberSuccess` indicates if the phone verification was successful.


# Frontend: Get Started

Get started building on DeSo with our Javascript SDK

### Setup

If you’re already familiar with a particular framework, feel free to set up a project using the documentation for your preferred tool (Create React App, Vite, Nextjs, Remix, Angular, Vue, etc).

If you're not sure, [our examples](https://github.com/deso-protocol/deso-examples-react) will be using [Create React App](https://create-react-app.dev/), which is a reasonable choice for getting a development environment up and running for quick prototyping.\
\
You can find the system requirements and installation steps on the Create React App [getting started page](https://create-react-app.dev/docs/getting-started).

Note that CRA’s default scaffolding uses vanilla javascript.\
\
If you’re comfortable with typescript and prefer to use it, [see this section](https://create-react-app.dev/docs/getting-started#creating-a-typescript-app) to get started. Otherwise, using vanilla javascript is a reasonable choice.

Once you have your app up and running with the default scaffolding, we’ll install the DeSo identity package and look at some examples.

### Installation

[The DeSo Protocol SDK](https://www.npmjs.com/package/deso-protocol) is used for core functionality when building an application for the DeSo blockchain: logging in, logging out, signing and submitting transactions, and more. \
\
NPM: <https://www.npmjs.com/package/deso-protocol>\
Github: <https://github.com/deso-protocol/deso-workspace/tree/main/libs/deso-protocol>

\
In the root of your application run:

```
npm i deso-protocol
```

And now you should be ready to start building!

## Configuration

Change the identity library’s behavior based on the needs of your app.

### Transaction spending limit options

Setting transaction spending limit options will determine what permissions your users will see when logging into your app, and the amount in DeSo your app can spend on their behalf.

On DeSo, every user gets a main or ***owner*** keypair generated for them when they create an account for the first time.\
\
The owner key is able to sign ***any*** transaction on behalf of the user, including spending ***all*** of their money, and transferring **all** of their NFTs or tokens!

It wouldn’t be a good idea to give every app the user interacts with direct access to this key. But we also don’t want to make users have to manually approve *every single transaction* that an app wants them to do.\
\
Can you imagine using Twitter if every like and comment required an annoying approval popup?

The solution is to allow apps to generate **subkeys** or ***derived*** keys that have a limited set of permissions, approved by the ***owner*** key.\
\
This looks as follows:

* User creates an account for the first time, generating an ***owner*** public/private keypair that is stored in DeSo Identity (stored locally in the browser, but on a distinct domain that is not accessible to apps).<br>
* User gets some starter $DESO coins to cover gas, either by entering their phone number or buying some.<br>
* App generates a ***derived*** key, which can just be any random keypair, and a transaction granting this derived key certain permissions, e.g. the ability to post 3 times on the user’s behalf.<br>
* Once the derived key approval transaction is generated, the DeSo Identity wallet can prompt the user to ***approve*** it, thus signing the transaction with the user’s ***owner*** public key.<br>
* Once an approve txn is signed by the user’s owner public key, it can be ***broadcast*** to the DeSo blockchain, which then gives the ***derived*** key the desired permissions.<br>
* The app can then happily sign transactions on the user’s behalf, without the user having to worry about the app stealing their funds (also known as getting **rug-pulled** or **rugged**).

In this example, we will ask users for permission to create an unlimited number of posts and make an unlimited number of transfers until they meet the global limit of 1 $DESO.

```
import { configure } from 'deso-protocol';

configure({
  spendingLimitOptions: {
    // NOTE: this value is in Deso nanos, so 1 Deso * 1e9
    GlobalDESOLimit: 1 * 1e9 // == 1 Deso
    // Map of transaction type to the number of times this derived key is
    // allowed to perform this operation on behalf of the owner public key
    TransactionCountLimitMap: {
      BASIC_TRANSFER: 'UNLIMITED', // Sending/receiving DESO is a "basic transfer"
      SUBMIT_POST: 'UNLIMITED',
    },
  }
});
```

**Important:** You’ll want to make sure you call configure only once prior to calling any other identity methods.

Note that even though we approve an unlimited number of **basic transfer** transactions in the above configure() call, we cannot take more than 1 $DESO from the user’s wallet before we have to pop up an approval again.

This is a good thing for the user!

While you’ll typically want to ask for specific permissions in a production app, it is possible to ask for unlimited access for prototyping or quickly testing things.\
\
This example requests approval for unlimited access:

```
import { configure } from 'deso-protocol';

configure({
  spendingLimitOptions: {
    IsUnlimited: true
  }
});
```

### App Name

`appName` is used to identify the app that authorizes a derived key.\
\
This can be used to group and identify derived keys that have been issued by a given app. If you don’t set the appName, the domain name your app is running on will be used by default.

```
import { configure } from 'deso-protocol';

configure({
  appName: 'My Cool App',
  spendingLimitOptions: {
    IsUnlimited: true
  }
});
```

Soon, users will be able to easily see all the apps they’ve used, and what permissions they’ve granted them (this is why setting a good app name is helpful!).\
\
Users will also be able to disable permissions from one unified dashboard.

### Next steps

Next, we’ll look at some basic [examples of common scenarios.](https://github.com/deso-protocol/deso-examples-react)


# Frontend: React Example

Use this React example to start building your first app on DeSo

This is a simple [Create React App](https://create-react-app.dev/docs/getting-started) project, but these examples can be easily ported to your preferred framework or build tool.

Github: <https://github.com/deso-protocol/deso-examples-react>

### How to run these examples locally

Run the following in your terminal

```
git clone https://github.com/deso-protocol/deso-examples-react.git
cd deso-examples-react
npm i
npm run start
```

### How to use this repository

If you want to port these examples to your own app, set up a project using the docs for your preferred tool (Create React App, Vite, Nextjs, Remix, Angular, Vue, etc).

If you're not sure, Create React App is a reasonable choice for getting a development environment up and running for quick prototyping/experimenting.

Next, install the [DeSo Protocol SDK](https://www.npmjs.com/package/deso-protocol) using your preferred package manager:

```
# npm
npm i deso-protocol

# yarn
yarn add deso-protocol
```

Finally, use the examples found in this repo to help you build social features for your application.

There are lots of comments throughout the code, but if anything is unclear, please open an issue!

### Examples

* [Configuration](https://github.com/deso-protocol/deso-examples-react/blob/main/src/routes/root.jsx#L7)
* [Login](https://github.com/deso-protocol/deso-examples-react/blob/main/src/components/nav.jsx#L27)
* [Logout](https://github.com/deso-protocol/deso-examples-react/blob/main/src/components/nav.jsx#L31)
* State Sync
  1. [Create a react context](https://github.com/deso-protocol/deso-examples-react/blob/main/src/contexts.js#L7)
  2. [Set up useState hook](https://github.com/deso-protocol/deso-examples-react/blob/main/src/routes/root.jsx#L18)
  3. [Set up useEffect hook](https://github.com/deso-protocol/deso-examples-react/blob/main/src/routes/root.jsx#L24)
  4. [Subscribe to identity](https://github.com/deso-protocol/deso-examples-react/blob/main/src/routes/root.jsx#L40)
  5. [Instantiate a context provider](https://github.com/deso-protocol/deso-examples-react/blob/main/src/routes/root.jsx#L117)
  6. [Use state from identity anywhere](https://github.com/deso-protocol/deso-examples-react/blob/main/src/components/nav.jsx#L8)
  7. [React to changes in your code](https://github.com/deso-protocol/deso-examples-react/blob/main/src/components/nav.jsx#L16)
* [Check permissions](https://github.com/deso-protocol/deso-examples-react/blob/main/src/routes/sign-and-submit-tx.jsx#L8)
* [Request permissions](https://github.com/deso-protocol/deso-examples-react/blob/main/src/routes/sign-and-submit-tx.jsx#L50)
* [Create, sign, submit a transaction](https://github.com/deso-protocol/deso-examples-react/blob/main/src/routes/sign-and-submit-tx.jsx#L61)


# Frontend: NextJS Example

DeSo Frontend Starter for NextJS and React apps

**Primary Contributor & Maintainer:** [**@brootle**](https://focus.xyz/brootle)&#x20;

A modern frontend web application built using **Next.js App Router** and designed to integrate with the [**DeSo Protocol**](https://github.com/deso-protocol) — a decentralized social blockchain platform.

📦 **Repository**: [brootle/deso-starter-nextjs-plus](https://github.com/brootle/deso-starter-nextjs-plus)

This starter includes:

* DeSo authentication via Identity service
* Profile selector and alternate identity switching
* Advanced commenting system with optimistic updates
* Network-resilient data fetching and caching
* Clean UI component system (Buttons, Inputs, Dropdowns, Select, etc.)
* Support for Floating UI dropdowns and portals
* Dark/light theming via CSS variables
* Storybook for component exploration

***

### 🔥 Features

* 🔐 **DeSo Auth**: Log in using DeSo Identity
* 👥 **Alt Profile Switcher**: Switch between multiple public keys
* 🔎 **Search Profiles**: Find users by public key or username
* 📝 **Post Support**: Read and create posts on the DeSo blockchain
* 💬 **Advanced Comments**: Inline replies with optimistic updates and smart caching
* 🌐 **Network Resilient**: Handles offline/online transitions gracefully
* 👻 **Profileless Accounts**: Fully functional even without a user profile
* 🎨 **Component Library**: Custom Select, MenuItem, Avatar, and Dropdown components
* 🌐 **Responsive UI**: Built with modular CSS and theme tokens
* 📦 **Floating UI**: Precise positioning via `@floating-ui/react`
* 🧱 **Scalable Structure**: Clean folder structure for extending easily

#### 🧠 **State Management with React Query**

This starter uses [**TanStack React Query**](https://tanstack.com/query/latest) for efficient, declarative data fetching and caching with enterprise-grade reliability.

✅ **Core Benefits:**

* Smart caching and deduplication of network requests
* Declarative `useQuery` / `useMutation` hooks
* Built-in error/loading states
* React Query Devtools support (optional)

✅ **Network Resilience Features:**

* **Wake-from-sleep protection** - No more "failed to fetch" errors when laptop wakes up
* **Smart retry logic** - Won't retry when offline or for client errors
* **Progressive retry delays** - Intelligent backoff (1s, 2s, 4s, 8s, max 15s)
* **Offline awareness** - Graceful handling of network transitions
* **Centralized configuration** - Consistent behavior across all pages

#### 💬 **Advanced Comment System**

The commenting system features sophisticated state management and user experience optimizations:

✅ **Real-time Features:**

* **Optimistic updates** - Comments appear instantly while syncing to blockchain
* **Local/remote merging** - Seamlessly combines user's new comments with server data
* **Infinite pagination** - Load more comments on demand
* **Smart deduplication** - Prevents duplicate comments across page loads

✅ **User Experience:**

* **Inline replies** - Reply directly from any post without page navigation
* **Expand/collapse** - Show/hide comment threads with state persistence
* **Comment promotion** - Local comments become permanent after server sync
* **Visual feedback** - Clear loading states and error handling

Usage examples include:

* Fetching user profiles by public key or username
* Fetching posts and comments with infinite scroll
* Creating replies with optimistic UI updates
* Managing complex UI state like comment visibility
* Handling username → public key resolution for notifications and feeds

Query keys are centralized in `/queries/queryKeys.js`, UI keys in `/queries/uiKeys.js`, and network configuration in `/queries/queryClientConfig.js` for consistency and maintainability.

> 🔧 Profile editing and mutations use `invalidateQueries()` for cache synchronization and support optimistic updates.

### 🚀 Getting Started

#### 1. Clone the repository

```bash
git clone https://github.com/brootle/deso-starter-nextjs-plus.git
cd deso-starter-nextjs-plus
```

#### 2. Install dependencies

```bash
npm install
```

#### 3. Start the dev server

```bash
npm run dev
```

Visit `http://localhost:3000` to view the app.

***

### 🧪 Storybook

Run Storybook to browse UI components in isolation:

```bash
npm run storybook
```

Opens at: `http://localhost:6006`

***

### 🛠 Tech Stack

* **Framework**: [Next.js App Router](https://nextjs.org/docs/app) (v15.2.4)
* **UI Logic**: React 19 + CSS Modules
* **Data Fetching & Caching**: [React Query v5](https://tanstack.com/query/latest) with network-aware configuration
* **State Management**: React Context (Auth, User) + React Query for UI state
* **Floating Dropdowns**: [`@floating-ui/react`](https://floating-ui.com/)
* **DeSo Identity**: Authentication via DeSo Identity service
* **Theming**: CSS variable-based dark/light support

***

### 🧩 Folder Structure

```
/api               → DeSo API abstraction hooks and handlers
/app               → Next.js App Router structure (routes, pages, layout)
/assets            → Static assets like icons and illustrations
/components        → Reusable UI components (Button, Select, Input, etc.)
/config            → Environment-independent constants (e.g. API base URLs)
/context           → Global state via React Context API (Auth, User, QueryProvider)
/hooks             → Custom React hooks (e.g. useClickOutside, useToast)
/layouts           → Shared layout components (MainLayout, etc.)
/queries           → React Query configuration and key definitions
  ├── queryKeys.js         → API query keys
  ├── uiKeys.js           → UI state keys  
  ├── queryClientConfig.js → Network-aware configuration
  └── index.js            → Clean exports
/styles            → Theme system and shared styles (CSS Modules + variables)
/utils             → Helper functions (auth, DeSo profiles, tokens)
```

***

### 🔧 Query Configuration

The app features a sophisticated React Query setup optimized for reliability:

#### **Network-Aware Retry Logic**

```javascript
// Won't retry when offline or for client errors (4xx)
// Uses progressive delays: 1s → 2s → 4s → 8s → max 15s
const networkAwareRetry = (failureCount, error) => {
  if (!navigator.onLine) return false;
  if (error?.status >= 400 && error?.status < 500) return false;
  return failureCount < 2;
};
```

#### **Wake-from-Sleep Protection**

```javascript
// Prevents "failed to fetch" errors when laptop wakes up
refetchOnReconnect: false,  // Key setting
refetchOnWindowFocus: false,
```

#### **Smart Cache Management**

* **API queries**: 2-minute stale time, 10-minute cache time
* **Search queries**: 30-second stale time for fresh results
* **Comments**: Infinite stale time for persistent threading
* **UI state**: Cached for consistent user experience

***

### 📜 License

This project is open-sourced under the MIT License.

***

### 🤝 Contributing

Pull requests are welcome! Open issues or suggestions any time.

***

### 🌍 Credits

Built using the [DeSo Protocol](https://github.com/deso-protocol) — the decentralized social blockchain.

***

### 🪲 Known Issues and Bug Reports

During development, several minor issues were identified with the DeSo backend API:

#### Open Issues

* **Unresolved:** See [this bug report](https://github.com/deso-protocol/backend/issues/736) for details on an issue that remains open.

#### Resolved Issues

* **Fixed:** A previously reported bug has been addressed. Refer to [this issue](https://github.com/deso-protocol/backend/issues/725) for more information.

If you encounter additional issues, please report them via the appropriate GitHub repository.


# Backend: Config

Overview of the configuration flags for running your own backend

**Core Protocol:** Trying to build the next great social app on top of the DeSo blockchain or running a node and want to know the ins-and-outs of all the endpoints?

This section is for you.

Compared to private, monopolized Web2 social media, all of the data on the DeSo blockchain is public and lives on-chain.

This means that **anybody can access this information and build their own application** using that data.&#x20;

However, blockchains require transactions and cryptography to validate information.&#x20;

We know this can be a hassle, so we've built this API along with the [DeSo Identity](/deso-identity/identity) service to make it easy for you, the developer, to focus on what matters: building your application.&#x20;

There is no need to define and maintain your own database schema and write logic to extract data from the chain to get started building and writing and reading new data on-chain.&#x20;

To write data to the blockchain, all you need is the Backend API, which you can use to construct transactions with the[Construct: API](/deso-backend/construct-transactions) and then submit them with [Transactions: API](/deso-backend/transaction-utilities#submit-a-transaction) endpoint, and Identity, which you can use to [Endpoints](/deso-identity/iframe-api/endpoints#sign) transactions.

To read data, you can use our [Data: API](/deso-backend/api) endpoints to retrieve everything you need.

As a developer, all you need to do is implement the frontend (or modify the reference implementation) and any custom logic around the data you receive from the backend endpoints.

If you're running your own node and using the reference backend implementation, there are a wide variety of flags that are available to you to manage behavior and functionality on your node.

Each section below describes a set of flags related to certain functionality.


# Onboarding

Description of flags related to the Onboarding proces and starter DESO

Note: Starter DESO Seed is required in order to send DESO to users for verifying their phone number or for verifying through Jumio.

## Starter DESO Seed

`--starter-deso-seed`

Type: String

Default: None

Seed phrase that is used to send DESO to users who go through [Phone Number Verification](/deso-backend/configuration/phone-number-verification) or [Broken mention](broken://pages/EsyXNU6ElMFAwUDXW5MB), and to [#comp-profile-creation](#comp-profile-creation "mention")

## Starter DESO Nanos

`--starter-deso-nanos`

Type: Integer

Default: 1000000

The amount of DESO given for verifying a phone number. Only active if [#starter-deso-seed](#starter-deso-seed "mention") is set and funded. 1000000 nanos = 0.001 DESO

## Starter Prefix Nanos Map

`--starter-prefix-nanos-map`

Type: String

Default: None

A comma-separated list of 'prefix=nanos' mappings, where prefix is a phone number prefix such as "+1". These mappings allow the node operator to specify custom amounts of DESO to users verifying their phone numbers based on the country they're in. This is useful as it is more expensive for attackers to get phone numbers from certain countries. An example string would be '+1=2000000,+2=2000000' which would pay user's with US phone number 0.002 DESO (2000000 nanos)

## Comp Profile Creation

`--comp-profile-creation`

Type: Boolean

Default: False

If true, the public key derived from the [#starter-deso-seed](#starter-deso-seed "mention") will send DESO to a public key when the public key makes a request to [Social Transactions API](/deso-backend/construct-transactions/social-transactions-api#update-profile) to construct an UpdateProfile transaction that creates a profile if the public key has verified their phone number or verified themselves thru the Jumio process.

## Min Satoshis For Profile

`--min-satoshis-for-profile`

Deprecated


# Phone Number Verification

Description of flags related to verifying phone numbers with Twilio

Note: All flags below are required in order for the phone number verification service to work properly. You'll need to setup an account with [Twilio](https://www.twilio.com/)

## Twilio Account SID

`--twilio-account-sid`

Type: String

Default: None

Twilio account SID (string id). Twilio is used for sending verification texts. See [twilio documentation](https://www.twilio.com/docs/verify/api/verification) for more info.

## Twilio Auth Token

`--twilio-auth-token`

Type: String

Default: None

Twilio authentication token. See [twilio documentation](https://www.twilio.com/docs/verify/api/verification) for more info.

## Twilio Verify Service ID

`--twilio-verify-service-id`

Type: String

Default: None

ID for a verify service configured within Twilio (used for verification texts)


# Global State

Description of flags related to your node's global state database

## Global State Remote Node

`--global-state-remote-node`

Type: String

Default: None

The IP:PORT or DOMAIN:PORT corresponding to a node that can be used to set/get global state. When this is not provided, global state is set/fetched from a local DB. Global state is used to manage things like user data, e.g. emails, that should not be duplicated across multiple nodes.

## Global State Remote Secret

`--global-state-remote-secret`

Type: String

Default: None

When a remote node is being used to set/fetch global state, a secret is also required to restrict access.

## Expose Global State

`--expose-global-state`

Type: Boolean

Default: False

If true, other nodes are able to request exposed attributes of your global state. Currently, this allows other nodes to fetch verified usernames, blacklist, graylist, and posts that have been added to the global feed on your node.

## Global State API URL

`--global-state-api-url`

Type: String Default: None Example: `--global-state-api-url https://node.deso.org` or `GLOBAL_STATE_API_URL=https://node.deso.org`

Fully formed URL to use to fetch global state data. Only used if expose-global-state is false. If not provided, use own global state. The URL must point to another node that has `true` for its [#expose-global-state](#expose-global-state "mention") value. This will allow you to fetch verified usernames, blacklist, graylist, and posts that have been added to the global feed on the requested URL.


# Admins

Description of flags related to admin access on your node.

## Admin Public Keys

`--admin-public-keys`

Type: String\[]

Default: \[]

A list of public keys which gives users access to the admin panel. If '\*' is specified as a key, anyone can access the admin panel. You can add a space and a comment after every public key and leave a note about who the public key belongs to. Admins can add posts to the global feed, manage the whitelist/blacklist/graylists, among other admin functionality.

## Super Admin Public Keys

`--super-admin-public-keys`

Type: String\[]

Default: \[]

A list of public keys which gives users access to the super admin panel. If '\*' is specified as a key, anyone can access the super admin panel. You can add a space and a comment after every public key and leave a note about who the public key belongs to. Be careful who you grant Super Admin access to - Super admins can manage the reserve price at which you sell DESO, the fee you assess on DESO purchases, among other critical configurations.


# Web Security

Description of flags related to your node's web security

## Access Control Allow Origins

`--access-control-allow-origins`

Type: String\[]

Default: \["\*"]

Accepts a comma-separated lists of origin domains that will be allowed as the Access-Control-Allow-Origin HTTP header. Defaults to \* if not set which allows all origin domains.

## Secure Header Development

`--secure-header-development`

Type: Boolean

Default: true

If set, runs our secure header middleware in development mode, which disables some of the options. The default is true to make it easy to run a node locally. See <https://github.com/unrolled/secure> for more info.

## Secure Header Allow Hosts

`--secure-header-allow-hosts`

Type: String\[]

Default: \[],

This is the domain that our secure middleware will accept requests from. We also set the HTTP Access-Control-Allow-Origin

##


# Media

Description of flags related to uploading media on your node

[Images](/deso-backend/configuration/media/images)

[Videos](/deso-backend/configuration/media/videos)


# Images

Description of flags related to uploading images on your node

## GCP Credentials Path

`--gcp-credentials-path`

Type: String

Default: None

Path to google credentials necessary to upload to the bucket specified in [#gcp-bucket-name](#gcp-bucket-name "mention")

## GCP Bucket Name

`--gcp-bucket-name`

Type: String

Default: None

Name of bucket to store images


# Videos

Description of flags related to uploading videos on your node

## Cloudflare Stream Token

`--cloudflare-stream-token`

Type: String

Default: None

API Token with Edit access to Cloudflare's stream service

## Cloudflare Account ID

`--cloudflare-account-id`

Type: String

Default: None

Cloudflare Account ID


# Hot Feed

Description of flags related to running the hot feed routine on your node

## Run Hot Feed Routine

`--run-hot-feed-routine`

Type: Boolean

Default: False

If set, runs a go routine that accumulates 'hotness' scores for posts in the last 24hrs. This can be used to serve a 'hot' feed.


# Selling $DESO

Description of flags related to selling DESO on your Node

Note: [#buy-deso-seed](#buy-deso-seed "mention") is required for purchasing via all three methods:

* [Wyre - Buy with USD](/deso-backend/configuration/selling-usddeso/wyre-buy-with-usd)
* [Buy with BTC](/deso-backend/configuration/selling-usddeso/buy-with-btc)
* [Buy with ETH](/deso-backend/configuration/selling-usddeso/buy-with-eth)

## Buy DESO Seed

`--buy-deso-seed`

Type: String

Default: None

Seed phrase from which DESO will be sent for orders placed through Wyre and 'Buy With BTC'  and 'Buy with ETH' purchases


# Wyre - Buy with USD

Description of flags related to selling DESO for BTC with Wyre on your Node

Note: You will need to work with [Wyre](https://www.sendwyre.com/) in order to set up an integration. Wyre will take credit card payment from your users and in exchange send you BTC to the address specified at [Buy with BTC](/deso-backend/configuration/selling-usddeso/buy-with-btc#buy-deso-btc-address)

## Wyre URL

`--wyre-url`

Type: String

Default: None

Wyre API URL. For production purposes, this should be <https://api.sendwyre.com>. For testing purposes, this should be [https://api.testwyre.com](<	https://api.testwyre.com>)

## Wyre Account ID

`--wyre-account-id`

Type: String

Default: None

Wyre account ID

## Wyre API Key

`--wyre-api-key`

Type: String

Default: None

API Key for Wyre account

## Wyre Secret Key

`--wyre-secret-key`

Type: String

Default: None

Secret key for Wyre account


# Buy with BTC

Description of flags related to selling DESO for BTC on your Node

## Buy DESO BTC Address

`--buy-deso-btc-address`

Type: String

Default: None

BTC Address that will receive BTC for all Wyre Wallet Orders and 'Buy With BTC' purchases

## BlockCypher API Key

`--block-cypher-api-key`

Type: String

Default: None

When specified, this key is used to power the BitcoinExchange flow and to check for double-spends in the mempool


# Buy with ETH

Description of flags related to selling DESO for ETH on your Node

## Buy DESO ETH Address

`--buy-deso-eth-address`

Type: String

Default: None

ETH Address which will receive ETH for all 'Buy With ETH' purchases

## Infura Project ID

`--infura-project-id`

Type: String

Default: None

Project ID for Infura requests. Infura is used to make requests to [ETH's JSON RPC API.](https://eth.wiki/json-rpc/API) Create a new project at <https://infura.io/>


# Analytics

Description of flags related to tracking user analytics on your node

## Amplitude Key

`--amplitude-key`

Type: String

Default: None

Client-side amplitude key for instrumenting user behavior.

## Amplitude Domain

\--amplitude-domain

Type: String

Default: api.amplitude.com

Deprecated


# Emails

Description of flags related to sending emails on your node

Note: You'll need to set up an account with [Sendgrid](https://sendgrid.com/)

## Sendgrid API Key

`--sendgrid-api-key`

Type: String

Default: None

Sendgrid API key

## Sendgrid Domain

`--sendgrid-domain`

Type: String

Default: None

Sendgrid domain

## Sendgrid Salt

`--sendgrid-salt`

Type: String

Default: None

Sendgrid salt for encoding data in emails

## Sendgrid From Name

`--sendgrid-from-name`

Type: String

Default: None

Sendgrid From Name

## Sendgrid From Email

`--sendgrid-from-email`

Type: String

Default: None

Sendgrid From Email

## Sendgrid Confirm Email ID

`--sendgrid-confirm-email-id`

Type: String

Default: None

Sendgrid confirmation email template ID


# Supply Monitoring

Description of flags related to running supply monitoring on your node

## Run Supply Monitoring Routine

`--run-supply-monitoring-routine`

Type: Boolean

Default: False

If true, run a goroutine to monitor total supply and rich list


# Construct: API

Descriptions of all Transaction Construction Endpoints

This section describes the endpoints used to construct transactions. All transactions must be signed — you can read about signing transactions in the [Identity Documentation](/deso-identity/iframe-api/endpoints#sign).

For a reference implementation of constructing, signing, and submitting a transaction, see [signAndSubmitTransaction](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L483) in frontend.

Transactions submit data to the DeSo blockchain. Transactions on the DeSo blockchain can represent social data, such as a profile update or a post, NFT actions (minting, selling, burning, etc.), and financial/creator coin transactions.

### Structure of response

Each transaction construction endpoint returns a similar response, so descriptions are included here instead of in each sample response.

Only `TxnMeta` is commented in the sample responses. Every transaction construction endpoint returns the following fields:

* `TotalInputNanos`: This is the total value in nanos of all the inputs specified in the transaction.<br>
* `ChangeAmountNanos`: This is the amount of change the transactor will receive when submitting this transaction.<br>
* `FeeNanos`: This is the amount the user pays in fees. `TotalInputNanos - ChangeAmountNanos - any other DeSo spent in transaction`.<br>
* `Transaction`:
  * `TxInputs`: This is an array of objects with two keys, TxID and Index. For the sake of brevity, the value of TxID is replace with ellipses in response samples provided on this page.<br>
  * `TxOutputs`: This is an array of objects with two keys, PublicKey and AmountNanos that specifies where the outputs will go and how much.<br>
  * `TxnMeta`: This is an object that varies based on the transaction type. It contains the metadata that describes the transaction. For example, in an Update Profile transaction, `TxnMeta` will include `NewUsername` and `NewProfilePic`.<br>
  * `ExtraData`: This is an object that can contain any key-value pairs that add additional information about a transaction.<br>
  * `Signature`: This will be null when received from these endpoints. Identity will provide a signature.<br>
  * `TxnTypeJSON`: This is an integer representing the type of the transaction.<br>
  * `PublicKey`: This is the public key of the transactor.<br>
* `TransactionHex`: Hex of the transaction. This is passed to identity to generate a signature.

Some transactions will have the following attributes:

* `TxnHashHex`: Hex of the transaction hash. This is used to check if a transaction has been successfully broadcast to the network with the Get Txn endpoint.<br>
* `SpendAmountNanos`: The amount of DeSo spent in a transaction not on fees. For example, in a creator coin purchase, this would be the amount of DeSo spent on buying creator coins.

## Data Types

### TransactionFee

`TransactionFees` are additional transaction outputs.&#x20;

These additional outputs are a way for both node operators (who can specify additional fees for all transactions of a certain type on their node) and app developers (who can specify additional fees when making a request to construct a transaction).

```json5
{
  "PublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public key of the user who will receive the additional output,
  "ProfileEntryResponse": <ProfileEntryResponse>, // This is only provided when TranssactionFees are retrieved through admin endpoints when managing node-leve transaction fees
  "AmountNanos": 10000, // The amount of DeSo in nanos this user should receive
}
```

For reference, `TransactionFee` is defined in the backend repo [here](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/admin_fees.go#L16).

## AccessGroupMember

`AccessGroupMembers`  are objects used when performing Access Group Member transactions which add, remove, or update members of an access group. These objects are only using in the construction of these transaction.

#### Attributes

* AccessGroupMemberPublicKeyBase58Check: the public key of the user who is being added, removed, or updated
* AccessGroupMemberKeyName: the access group key name belong to AccessGroupMemberPublicKeyBase58Check by which the user is being added to or removed from the group. &#x20;
* EncryptedKey: the private key of the access group is encrypted to the AccessGroupPublicKey of the member's access group. This must be left empty when removing a member from a group
* ExtraData: arbitrary key value data used to add details about this access group member&#x20;

```json5
{
  "AccessGroupMemberPublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s",
  "AccessGroupMemberKeyName": "default-key",
  "EncryptedKey": "someencryptedhexstring",
  "ExtraData": { "key": "value" },
}
```

##


# Social Transactions API

Description of endpoints used to construct Social Transactions on the DeSo blockchain

## Update Profile

<mark style="color:green;">`POST`</mark> `/api/v0/update-profile`

Create an Update profile transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Update profile transactions creates a profile update such as changing a username, description, profile picture, or founder reward.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L263).

Example usages in frontend:\
\- Make request to [Update Profile](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L263)\
\- Using Update Profile on the [Profile Update page](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/update-profile-page/update-profile/update-profile.component.ts#L170)

#### Request Body

| Name                                                          | Type               | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UpdaterPublicKeyBase58Chck<mark style="color:red;">\*</mark>  | String             | Public key of updater                                                                                                                                                                                                         |
| ProfilePublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of the profile if different from updater                                                                                                                                                                           |
| NewUsername<mark style="color:red;">\*</mark>                 | String             | Username                                                                                                                                                                                                                      |
| NewDescription<mark style="color:red;">\*</mark>              | String             | Description                                                                                                                                                                                                                   |
| NewProfilePic<mark style="color:red;">\*</mark>               | String             | Base64 encoded profile picture                                                                                                                                                                                                |
| NewCreatorBasisPoints<mark style="color:red;">\*</mark>       | uint64             | Founder reward in basis points - e.g. 1000 basis points = 10% founder reward                                                                                                                                                  |
| NewStakeMultipleBasisPoints                                   | uint64             | <p>Deprecated</p><p><del>Staking Reward</del></p>                                                                                                                                                                             |
| IsHidden                                                      | boolean            | Deprecated                                                                                                                                                                                                                    |
| ExtraData                                                     | map\[string]string | extra data, values must be strings. This is an arbitrary json object that can be used to add extra metadata on a profile                                                                                                      |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>        | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                               | TransactionFees]   | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successful construction of an update profile transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "TotalInputNanos": 933084474,
  "ChangeAmountNanos": 933082094,
  "FeeNanos": 2380,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 933082094
      }
    ],
    "TxnMeta": {
      "ProfilePublicKey": null, // Public key of the profile being updated if different from transactor
      "NewUsername": "dGVzdGFz", // New username for this public key
      "NewDescription": "", // New descrpition for this public key
      "NewProfilePic": "ZGF0YTppbWFnZS93ZWJwO2Jhc2U2NCxVa2xHUmtZR0FBQlhSVU..." // New profile picture for this public key
      "NewCreatorBasisPoints": 10000, // New founder reward percentage in basis points 
      "NewStakeMultipleBasisPoints": 12500, // Deprecated
      "IsHidden": false // Is this profile hidden
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null, // Any additional keys in the ExtraData field of the request body will be included here
    "Signature": null,
    "TxnTypeJSON": 6
  },
  "TransactionHex": "015959c32e6e39a99ce8ca05835a291e4e0ba6b203138aecfc4a527e6d992dd2f9000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45eee7f6bc03068f11000674657374617300ff10646174613a696d6167652f776562703b6261736536342c556b6c47526b59474141425852554a51566c413457416f4141414149414141415977414154674141566c41344947594641414477467743644153706b41453841506e30326c30656b6f7949684e525a4f714a415069574d417667733550456455534b616f6f39454c4f733131766647725871792f7453494d683646666e67684c6f4d55724c6674536b6c6b4b676555556842646d584d6f4e6f516a53654b772b504e3166356f6764576154694a4a715975427a4c6c304e625359312b2b6a4f3434584e347149326c6c69485768484e55433677467a506e56796664492b446c55667a3053594c306a4b364139417074414850333367766d41344247354f75776c7443736f37494a5a34585861703975524c6f6f5541433573395736325a4f69427238723941584d462f4b4d6f586e463270634e423853506e786b4c364941442b377074595a70714b746f65494f4a64375877724c7844437a43784b7162644b5877526d73456553582b6e4f6f6536616f355837727a62352b4b7133524b4275336c6b4c34595944586f464d52435444514a6f36686a7a436b7572524c62765a4844494b776765534f4d4252507347776e42614f65723934534b692f397379397a624a674b665947686d5764366b4a2b5534476e51654e67663468746370593975513552782b7776596533422f5766346c57796a494150596d3934634c41524e427258384935354149565064396a3773776d59764f706b7738674c6a6d796c573351786c35594e52723550675767477934574f49625665797635645334793851473852616c664b4c555575355533533773746d582b486f7968575a6e6b6b51586b534235304a584a2f5541686f42785977614d683746537a515158705a72487735436a7935474f4b3344536449412b4861746d702b6d516e666859417276644d5a636565506453516b6438496c757851736b6b4a6c46774176787374664331526d3054616c4d383831714a727473394947316b625431652f55686e626e56634f386845346e454364484777764d505862706e6a57696142624a574b513263533444514b2b474f454e35322f495073582f444d716c57794f756f5168383751757933794b736a6d30594133692f4c64502b7a575a2b4d564461315932544b6b64517558546d4254646f42763135473459356d545158644a417733585a64514e2b67766675314134564a38663731712f304c6c362f614e5034557a6d6c76642f6f702b47394d664f6d50725651324945512b6c314b6c64784f4c64452b665877314e386c6f696f5478467a45673757787163384844727672345247674532675743485343792f56676b6342524a4a4b7452414c564b486e766e763379417a3838637a35494e517868624e6354472b326a78627a4a746831762b3845562b59663578685a762b4b4770796d65503558656847346435664f4a6848386a58613277493138754736364b4d4376676a6d354d6541322f3654764961736546774d31794f367a624a624d4c75776547513739792f3167415a45367844617272784c426a7459727975464930506d4e356e4f58482f412f4b472b4f6964304173316d7776697a47434e77346e41674d496d614c30765653665669317a6a524e5a4e496c6d362f446d6e434550376639594c4d746139304f595437474c6e417170656d63326d547a6d4c6a4c65547855646e684b56503532382b733946513944724a6476336151303741554655724b5436466c434a69784c6b474765393943523565483952372b586f4e6a6e6f374c556d47774e74525443345557384e4263464144303677784d5a6c4d57474c435a57304c6b6833446e6572675a644a766e714a44465a69714969776b6d2f6c6b574e2f53442f2f6e3659504e335635745663654735654970626f2b6d74323856634871767568567a4a6639657471767650324b36594a6943576e507175316f4e3461422b50633535492b3157707753464b4f654831326566472b4b76303274443879594a7a52413554627064575877324f716d7a4f415a4f453370337a636e305a314952327079535a6563704757666b6d7243666d414f2b426a705353426974546e6a6843374375364755772f657a75504b5463302f3446784c75695a5630464472596b50726c6d484a784973785232335936724451583630486763456b724f485957774c6a765632594474303541724e382b4d4159565939546e7851555a35744f537577314d6f41764e5a61306a474731366e554d6d696d5832514c6843732f485a587968345a6b704e4756637333746955556165704878304445767a656f62386d4375315a6d5073646b4173463741786b2f6373716a6f6d713430446c7453614b54622f732f7461756c6c4a476a425230466967497953634c577251624545574c4862533957553771536378583346304a4a363633664778736c7851524a386769696359336759346a6a4b7a65517547625a7469444339593471444a673067336e624d417377442b304d7735557a78446a4e44543670355a735034374f734d78365330536f4c37486f333165412b766d35616f4a745931456e6a4e45566f383750706a4f424376554b6e397078555037334b6b4f787333775355557030414556595355613641414141525868705a67414153556b7141416741414141474142494241774142414141414151414141426f42425141424141414156674141414273424251414241414141586741414143674241774142414141414167414141424d4341774142414141414151414141476d4842414142414141415a67414141414141414141345977414136414d414144686a4141446f41774141426741416b41634142414141414441794d5441426b5163414241414141414543417741416f41634142414141414441784d4441426f414d414151414141502f2f414141436f4151414151414141475141414141446f41514141514141414538414141414141414141904ed461002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000",
  "TxnHashHex": "0f042cc71b1489a81d4342e61b7f4bc6d60cf81579fe629dd94a68211730a027"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Submit Post

<mark style="color:green;">`POST`</mark> `/api/v0/submit-post`

Create a submit post transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect. \\

Submit post transactions handle all manipulation of posts. It can be used to create a post, update a post, hide a post, or repost a post.\
\
Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L1200).\
\
Example usages in frontend:\
\- Make Request to [Submit Post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1035)\
\- Using SubmitPost function to [create a new post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/feed/feed-create-post/feed-create-post.component.ts#L186)

#### Request Body

| Name                                                         | Type                                                       | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------ | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UpdaterPulicKeyBase58Check<mark style="color:red;">\*</mark> | String                                                     | Public key of the user who is making or updating the post                                                                                                                                                                     |
| PostHashHexToModify                                          | String                                                     | When provided, update the post that matches this hash instead of creating a new one                                                                                                                                           |
| ParentStakeID                                                | String                                                     | PostHashHex of the parent of this post if applicable. When set, it creates a comment on the parent                                                                                                                            |
| BodyObj<mark style="color:red;">\*</mark>                    | { Body: String, ImageURLs: String\[], VideoURLs: String\[] | The body of the post                                                                                                                                                                                                          |
| RepostedPostHashHex                                          | String                                                     | Hash of post that this post is reposting                                                                                                                                                                                      |
| PostExtraData                                                | Map\[String]String                                         | extra data, values must be strings. This is an arbitrary json object that can be used to add extra metadata on a post                                                                                                         |
| IsHidden                                                     | Boolean                                                    | When true, this post will be hidden                                                                                                                                                                                           |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>       | uint64                                                     | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                              | TransactionFee]                                            | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| InTutorial                                                   | Boolean                                                    | When true, perform additional checks to ensure user is at the correct point in the tutorial to execute a submit post transaction                                                                                              |

{% tabs %}
{% tab title="200: OK Successful construction of a submit post transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "TstampNanos": 1637774290019245600,
  "PostHashHex": "ef782e8a43e8ebcadbb869fc8c74ebaa263dad2eb79c4c39906ac201d7863e1e",
  "TotalInputNanos": 933082094,
  "ChangeAmountNanos": 933081867,
  "FeeNanos": 227,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 933081867
      }
    ],
    "TxnMeta": {
      "PostHashToModify": "ef782e8a43e8ebcadbb869fc8c74ebaa263dad2eb79c4c39906ac201d7863e1e", // Hex of Post Hash created or modified by this transaction
      "ParentStakeID": "5959c32e6e39a99ce8ca05835a291e4e0ba6b203138aecfc4a527e6d992dd2f9", // Hex of Parent Post hash created or modified by this transaction
      "Body": "eyJCb2R5IjoidGVzdCJ9", // Body of the post
      "CreatorBasisPoints": 1000, // deprecated 
      "StakeMultipleBasisPoints": 12500, // deprecated
      "TimestampNanos": 1637774290019245600, // timestamp of post creation
      "IsHidden": false // If true, this post is not included in responses from any endpoitns
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {
      "Node": "MQ=="
    },
    "Signature": null,
    "TxnTypeJSON": 5
  },
  "TransactionHex": "01e206ccc2406e80b6544af58e8c0e7415bfc064c80fb0d57855299b25c8adfb52000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c458be6f6bc03052000000f7b22426f6479223a2274657374227de807d461d9bcf5d6a1e1a2dd16002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c4501044e6f6465013100"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Follow

<mark style="color:green;">`POST`</mark> `/api/v0/create-follow-txn-stateless`

Create a follow/unfollow transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Follow transactions adds the creator to the list of creators followed by the follower. This creator will now appear on the creator's following feed.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L1463).

Example usages in frontend:\
\- Make request to [create follow txn stateless](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1291).\
\- Use CreateFollowTxn to [follow a creator](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/lib/services/follow/follow.service.ts#L39)

#### Request Body

| Name                                                           | Type               | Description                                                                                                                                                                                                                   |
| -------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| FollowerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of the follower                                                                                                                                                                                                    |
| FollowedPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of creator being followed                                                                                                                                                                                          |
| IsUnfollow<mark style="color:red;">\*</mark>                   | Boolean            | false if follow. true if unfollow                                                                                                                                                                                             |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>         | Uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                | TransactionFees\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed Follow transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "TotalInputNanos": 270953971,
  "ChangeAmountNanos": 270953749,
  "FeeNanos": 222,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 1
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 270953749
      }
    ],
    "TxnMeta": {
      "FollowedPublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S", // Public key of creator being followed by the transactor 
      "IsUnfollow": false // If true, this is an unfollow transaction
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 9
  },
  "TransactionHex": "01cf3f6ab70a2076dfcf1d3792f5c126947dd21b59e4bbc1b795f7924b34484be8010102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c4595da998101092202397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}JSON
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Send Diamonds

<mark style="color:green;">`POST`</mark> `/api/v0/send-diamonds`

Create a send diamond transaction. A send diamond transaction is a basic transfer transaction with some additional metadata. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Diamond transactions are a form of social tipping. A send diamond transaction will send DeSo from the sender the receiver as a reward for a certain post.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L2007).

Example usages in frontend:\
\- Make request to [Send Diamonds](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1393)\
\- Use SendDiamonds to [tip a creator for a post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/feed/feed-post-icon-row/feed-post-icon-row.component.ts#L430)

#### Request Body

| Name                                                           | Type              | Description                                                                                                                                                                                                                   |
| -------------------------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderPublicKeyBase58Check<mark style="color:red;">\*</mark>   | String            | Public key of user sending diamonds                                                                                                                                                                                           |
| ReceiverPublicKeyBase58Check<mark style="color:red;">\*</mark> | String            | Public key of user receiving diamonds                                                                                                                                                                                         |
| DiamondPostHashHex<mark style="color:red;">\*</mark>           | String            | Hash of post receiving diamond                                                                                                                                                                                                |
| DiamondLevel<mark style="color:red;">\*</mark>                 | int64             | Level of Diamond being given in this transaction                                                                                                                                                                              |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>         | Uint64            | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                | TransactionFee\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed a Send Diamond transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "SpendAmountNanos": 50000,
  "TotalInputNanos": 999997474,
  "ChangeAmountNanos": 999947186,
  "FeeNanos": 288,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
        "AmountNanos": 50000
      },
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 999947186
      }
    ],
    "TxnMeta": {},
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {
      "DiamondLevel": "Ag==", // Level of diamonds given. Note these are bytes
      "DiamondPostHash": "PkIhWhIKbp1ISBF/WCmixNn2kjYP0Ut42upIOnLRQtw=" // Bytes of Post Hash Hex of the post to which diamonds were given
    },
    "Signature": null,
    "TxnTypeJSON": 2
  },
  "TransactionHex": "013307a4f6ccc02e05077ce299d458e79dfb0fac7b24ad5849ab622c6726ad7176000202397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52d0860302aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45b2f7e7dc0302002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45020c4469616d6f6e644c6576656c01020f4469616d6f6e64506f737448617368203e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc00",
  "TxnHashHex": "a78b07488f4c6d10183298d38bc14d2f8cb898e5e13c1a6a053c8678d01507c1"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Like

<mark style="color:green;">`POST`</mark> `/api/v0/create-like-stateless`

Create a Like/Unlike transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Like transactions increment the count of likes on a given post. Unlike transactions decrement the count of likes on a given post.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L1090).

Example usages in frontend:\
\- Make request to [Create Like Stateless](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1376)\
\- Use CreateLike to [like a post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/feed/feed-post-icon-row/feed-post-icon-row.component.ts#L332)

#### Request Body

| Name                                                         | Type              | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ReaderPublicKeyBase58Check<mark style="color:red;">\*</mark> | String            | Public key of the liker                                                                                                                                                                                                       |
| LikedPostHashHex<mark style="color:red;">\*</mark>           | String            | PostHashHex of the post being liked                                                                                                                                                                                           |
| IsUnlike<mark style="color:red;">\*</mark>                   | Boolean           | If true, remove the like from ReaderPublicKeyBase58Check on this post. If false, add a like from ReaderPublicKeyBase58Check on this post                                                                                      |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>       | uint64            | Rate per KB                                                                                                                                                                                                                   |
| TrasactionFees                                               | TransactionFee\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed Like transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "TotalInputNanos": 999947186,
  "ChangeAmountNanos": 999946965,
  "FeeNanos": 221,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 1
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 999946965
      }
    ],
    "TxnMeta": {
      "LikedPostHash": [103,248,14,166,144,139,147,204,169,33,162,164,158,242,104,173,55,55,86,181,186,69,175,244,224,107,247,163,31,127,32,192], // Bytes of the Post Hash that was liked by this transaction
      "IsUnlike": false // If true, this is an unlike transaction
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 10
  },
  "TransactionHex": "0126eb328dda3195e2eae7d74c79aa0d95711da4948c33fdfa6c9e3e9b78c29dad010102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45d5f5e7dc030a213e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Send Direct Message

<mark style="color:green;">`POST`</mark> `/api/v0/send-dm-message`

Prepare a new message transaction to send a DM to another user. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.&#x20;

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/new_message.go#L258).

#### Request Body

| Name                                                                            | Type               | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderAccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark>    | String             | Public key of the user sending message                                                                                                                                                                                        |
| SenderAccessGroupPublicKeyBase58Check<mark style="color:red;">\*</mark>         | String             | Public key of the access group the sender is using for this message                                                                                                                                                           |
| SenderAccessGroupKeyName<mark style="color:red;">\*</mark>                      | String             | The name of the access group the sender is using for this message                                                                                                                                                             |
| RecipientAccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of the user who is the recipient of the message                                                                                                                                                                    |
| RecipientAccessGroupPublicKeyBase58Check<mark style="color:red;">\*</mark>      | String             | Public key of the access group of the recipient of the message                                                                                                                                                                |
| RecipientAccessGroupKeyNameName<mark style="color:red;">\*</mark>               | String             | The name of the access group of the recipient of the message                                                                                                                                                                  |
| EncryptedMessageText<mark style="color:red;">\*</mark>                          | String             | The content of the message to be sent. It is recommended that this is encrypted, but it can also be provided unencrypted                                                                                                      |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>                          | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                                 | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| ExtraData                                                                       | map\[String]String | arbitrary key value data                                                                                                                                                                                                      |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "TstampNanos": 0,
  "TotalInputNanos": 99965445,
  "ChangeAmountNanos": 99964924,
  "FeeNanos": 521,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [
          124,
          40,
          198,
          223,
          196,
          63,
          241,
          136,
          44,
          71,
          219,
          104,
          132,
          123,
          55,
          19,
          42,
          95,
          167,
          105,
          27,
          237,
          194,
          147,
          234,
          222,
          34,
          179,
          202,
          138,
          241,
          253
        ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 99964924
      }
    ],
    "TxnMeta": {
      "SenderAccessGroupOwnerPublicKey": [
        2,
        170,
        61,
        200,
        210,
        153,
        234,
        30,
        73,
        20,
        222,
        102,
        73,
        78,
        211,
        225,
        110,
        218,
        154,
        13,
        101,
        113,
        157,
        82,
        60,
        26,
        154,
        3,
        203,
        249,
        246,
        12,
        69
      ],
      "SenderAccessGroupKeyName": [
        100,
        101,
        102,
        97,
        117,
        108,
        116,
        45,
        107,
        101,
        121,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "SenderAccessGroupPublicKey": [
        2,
        76,
        64,
        36,
        39,
        178,
        223,
        208,
        159,
        28,
        11,
        190,
        92,
        27,
        153,
        251,
        147,
        126,
        52,
        183,
        95,
        105,
        4,
        169,
        85,
        96,
        149,
        15,
        225,
        158,
        141,
        195,
        5
      ],
      "RecipientAccessGroupOwnerPublicKey": [
        2,
        53,
        122,
        183,
        201,
        238,
        120,
        142,
        241,
        209,
        209,
        249,
        17,
        57,
        99,
        0,
        58,
        45,
        150,
        159,
        237,
        2,
        206,
        148,
        119,
        143,
        249,
        113,
        92,
        110,
        28,
        128,
        117
      ],
      "RecipientAccessGroupKeyName": [
        100,
        101,
        102,
        97,
        117,
        108,
        116,
        45,
        107,
        101,
        121,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "RecipientAccessGroupPublicKey": [
        3,
        58,
        32,
        241,
        0,
        86,
        77,
        118,
        184,
        236,
        157,
        99,
        193,
        98,
        31,
        170,
        245,
        45,
        3,
        40,
        58,
        71,
        38,
        98,
        127,
        10,
        28,
        246,
        151,
        222,
        231,
        32,
        238
      ],
      "EncryptedText": "BJmb1jiZf6mpEnLxrRrDjS10p5O+OyrBvgKCNX6Zoakz6/mlSUbb66jBfriuJoRdLix5ybOXJJil6l0lTS870atH+xhVgBTFnugqBAjlHVRzsjWD6blgFmHOYnv1lTY0QNfrfuQmEfIK6yRGHhqi/Pno/BBpHQ==",
      "TimestampNanos": 1675454263701542000,
      "NewMessageType": 0,
      "NewMessageOperation": 0
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {},
    "Signature": {
      "Sign": null,
      "RecoveryId": 0,
      "IsRecoverable": false
    },
    "TxnTypeJSON": 33
  },
  "TransactionHex": "017c28c6dfc43ff1882c47db68847b37132a5fa7691bedc293eade22b3ca8af1fd000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45fcafd52f21cc022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c452064656661756c742d6b657900000000000000000000000000000000000000000021024c402427b2dfd09f1c0bbe5c1b99fb937e34b75f6904a95560950fe19e8dc3052102357ab7c9ee788ef1d1d1f9113963003a2d969fed02ce94778ff9715c6e1c80752064656661756c742d6b657900000000000000000000000000000000000000000021033a20f100564d76b8ec9d63c1621faaf52d03283a4726627f0a1cf697dee720ee7604999bd638997fa9a91272f1ad1ac38d2d74a793be3b2ac1be0282357e99a1a933ebf9a54946dbeba8c17eb8ae26845d2e2c79c9b3972498a5ea5d254d2f3bd1ab47fb18558014c59ee82a0408e51d5473b23583e9b9601661ce627bf595363440d7eb7ee42611f20aeb24461e1aa2fcf9e8fc10691de9a8e08aea989aa01700002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Update Direct Message

<mark style="color:green;">`POST`</mark> `/api/v0/update-dm-message`

Prepare a new message transaction to update an existing DM. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/47bcc8a/routes/transaction.go#L1331).

#### Request Body

| Name                                                                 | Type               | Description                                                                                                                                                                                                                   |
| -------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderAccessGroupOwnerPublicKey<mark style="color:red;">\*</mark>    | String             | Public key of the user updating a DM                                                                                                                                                                                          |
| SenderAccessGroupPublicKey<mark style="color:red;">\*</mark>         | String             | Public key of the access group the sender used for the DM originally                                                                                                                                                          |
| SenderAccessGroupKeyName<mark style="color:red;">\*</mark>           | String             | The name of the access group the sender used to originally send the DM                                                                                                                                                        |
| RecipientAccessGroupOwnerPublicKey<mark style="color:red;">\*</mark> | String             | Public key of the user who received the DM                                                                                                                                                                                    |
| RecipientAccessGroupPublicKey<mark style="color:red;">\*</mark>      | String             | Public key of the access group to which this DM was originally sent                                                                                                                                                           |
| RecipientAccessGroupKeyName<mark style="color:red;">\*</mark>        | String             | The name of the access group to which this DM was originally sent                                                                                                                                                             |
| EncryptedMessageText<mark style="color:red;">\*</mark>               | String             | The updated content of the message. It is recommended that this is encrypted, but it can also be provided unencrypted.                                                                                                        |
| TimestampNanosString<mark style="color:red;">\*</mark>               | String             | String version of the timestamp nanos field of the original DM. This is used to uniquely identify a message.                                                                                                                  |
| MinFeeRateNanosPerKB                                                 | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                      | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| ExtraData                                                            | map\[String]String | arbitrary key value data                                                                                                                                                                                                      |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "TstampNanos": 0,
  "TotalInputNanos": 99965445,
  "ChangeAmountNanos": 99964924,
  "FeeNanos": 521,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [
          124,
          40,
          198,
          223,
          196,
          63,
          241,
          136,
          44,
          71,
          219,
          104,
          132,
          123,
          55,
          19,
          42,
          95,
          167,
          105,
          27,
          237,
          194,
          147,
          234,
          222,
          34,
          179,
          202,
          138,
          241,
          253
        ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 99964924
      }
    ],
    "TxnMeta": {
      "SenderAccessGroupOwnerPublicKey": [
        2,
        170,
        61,
        200,
        210,
        153,
        234,
        30,
        73,
        20,
        222,
        102,
        73,
        78,
        211,
        225,
        110,
        218,
        154,
        13,
        101,
        113,
        157,
        82,
        60,
        26,
        154,
        3,
        203,
        249,
        246,
        12,
        69
      ],
      "SenderAccessGroupKeyName": [
        100,
        101,
        102,
        97,
        117,
        108,
        116,
        45,
        107,
        101,
        121,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "SenderAccessGroupPublicKey": [
        2,
        76,
        64,
        36,
        39,
        178,
        223,
        208,
        159,
        28,
        11,
        190,
        92,
        27,
        153,
        251,
        147,
        126,
        52,
        183,
        95,
        105,
        4,
        169,
        85,
        96,
        149,
        15,
        225,
        158,
        141,
        195,
        5
      ],
      "RecipientAccessGroupOwnerPublicKey": [
        2,
        53,
        122,
        183,
        201,
        238,
        120,
        142,
        241,
        209,
        209,
        249,
        17,
        57,
        99,
        0,
        58,
        45,
        150,
        159,
        237,
        2,
        206,
        148,
        119,
        143,
        249,
        113,
        92,
        110,
        28,
        128,
        117
      ],
      "RecipientAccessGroupKeyName": [
        100,
        101,
        102,
        97,
        117,
        108,
        116,
        45,
        107,
        101,
        121,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "RecipientAccessGroupPublicKey": [
        3,
        58,
        32,
        241,
        0,
        86,
        77,
        118,
        184,
        236,
        157,
        99,
        193,
        98,
        31,
        170,
        245,
        45,
        3,
        40,
        58,
        71,
        38,
        98,
        127,
        10,
        28,
        246,
        151,
        222,
        231,
        32,
        238
      ],
      "EncryptedText": "BJmb1jiZf6mpEnLxrRrDjS10p5O+OyrBvgKCNX6Zoakz6/mlSUbb66jBfriuJoRdLix5ybOXJJil6l0lTS870atH+xhVgBTFnugqBAjlHVRzsjWD6blgFmHOYnv1lTY0QNfrfuQmEfIK6yRGHhqi/Pno/BBpHQ==",
      "TimestampNanos": 1675454263701542000,
      "NewMessageType": 0,
      "NewMessageOperation": 1
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {},
    "Signature": {
      "Sign": null,
      "RecoveryId": 0,
      "IsRecoverable": false
    },
    "TxnTypeJSON": 33
  },
  "TransactionHex": "017c28c6dfc43ff1882c47db68847b37132a5fa7691bedc293eade22b3ca8af1fd000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45fcafd52f21cc022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c452064656661756c742d6b657900000000000000000000000000000000000000000021024c402427b2dfd09f1c0bbe5c1b99fb937e34b75f6904a95560950fe19e8dc3052102357ab7c9ee788ef1d1d1f9113963003a2d969fed02ce94778ff9715c6e1c80752064656661756c742d6b657900000000000000000000000000000000000000000021033a20f100564d76b8ec9d63c1621faaf52d03283a4726627f0a1cf697dee720ee7604999bd638997fa9a91272f1ad1ac38d2d74a793be3b2ac1be0282357e99a1a933ebf9a54946dbeba8c17eb8ae26845d2e2c79c9b3972498a5ea5d254d2f3bd1ab47fb18558014c59ee82a0408e51d5473b23583e9b9601661ce627bf595363440d7eb7ee42611f20aeb24461e1aa2fcf9e8fc10691de9a8e08aea989aa01700002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Send Group Chat Message

<mark style="color:green;">`POST`</mark> `/api/v0/send-group-chat-message`

Prepare a new message transaction to send a new message to a group chat. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/new_message.go#L279).

#### Request Body

| Name                                                                            | Type               | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderAccessGroupOwnerPublicKey<mark style="color:red;">\*</mark>               | String             | Public key of the user sending the message                                                                                                                                                                                    |
| SenderAccessGroupPublicKeyBase58Check<mark style="color:red;">\*</mark>         | String             | Public key of the access group the sender is using for this message                                                                                                                                                           |
| SenderAccessGroupKeyName<mark style="color:red;">\*</mark>                      | String             | The name of the access group the sender is using for this message                                                                                                                                                             |
| RecipientAccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of the owner of the group chat to which this message is being sent                                                                                                                                                 |
| RecipientAccessGroupPublicKeyBase58Check<mark style="color:red;">\*</mark>      | String             | Public key of the access group of the group to which this message is being sent                                                                                                                                               |
| RecipientAccessGroupKeyName<mark style="color:red;">\*</mark>                   | String             | The name of the access group of the group to which this message is being sent                                                                                                                                                 |
| EncryptedMessageText<mark style="color:red;">\*</mark>                          | String             | The content of the message to be sent. It is recommended that this is encrypted, but it can also be provided unencrypted                                                                                                      |
| MinFeeRateNanosPerKB                                                            | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                                 | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| ExtraData                                                                       | map\[String]String | arbitrary key value data                                                                                                                                                                                                      |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "TstampNanos": 0,
  "TotalInputNanos": 99964924,
  "ChangeAmountNanos": 99964404,
  "FeeNanos": 520,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [
          0,
          181,
          221,
          137,
          163,
          14,
          242,
          109,
          87,
          223,
          212,
          11,
          198,
          179,
          103,
          8,
          167,
          83,
          95,
          234,
          234,
          183,
          108,
          162,
          43,
          88,
          151,
          44,
          163,
          213,
          244,
          136
        ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 99964404
      }
    ],
    "TxnMeta": {
      "SenderAccessGroupOwnerPublicKey": [
        2,
        170,
        61,
        200,
        210,
        153,
        234,
        30,
        73,
        20,
        222,
        102,
        73,
        78,
        211,
        225,
        110,
        218,
        154,
        13,
        101,
        113,
        157,
        82,
        60,
        26,
        154,
        3,
        203,
        249,
        246,
        12,
        69
      ],
      "SenderAccessGroupKeyName": [
        100,
        101,
        102,
        97,
        117,
        108,
        116,
        45,
        107,
        101,
        121,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "SenderAccessGroupPublicKey": [
        2,
        76,
        64,
        36,
        39,
        178,
        223,
        208,
        159,
        28,
        11,
        190,
        92,
        27,
        153,
        251,
        147,
        126,
        52,
        183,
        95,
        105,
        4,
        169,
        85,
        96,
        149,
        15,
        225,
        158,
        141,
        195,
        5
      ],
      "RecipientAccessGroupOwnerPublicKey": [
        2,
        170,
        61,
        200,
        210,
        153,
        234,
        30,
        73,
        20,
        222,
        102,
        73,
        78,
        211,
        225,
        110,
        218,
        154,
        13,
        101,
        113,
        157,
        82,
        60,
        26,
        154,
        3,
        203,
        249,
        246,
        12,
        69
      ],
      "RecipientAccessGroupKeyName": [
        97,
        32,
        115,
        117,
        112,
        101,
        114,
        32,
        99,
        111,
        111,
        108,
        32,
        103,
        114,
        111,
        117,
        112,
        99,
        104,
        97,
        116,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "RecipientAccessGroupPublicKey": [
        3,
        3,
        94,
        26,
        126,
        158,
        42,
        200,
        157,
        157,
        221,
        254,
        78,
        232,
        48,
        73,
        48,
        155,
        57,
        206,
        208,
        107,
        131,
        252,
        109,
        168,
        55,
        150,
        14,
        66,
        225,
        84,
        213
      ],
      "EncryptedText": "BOjPxOvQ9V9hLjd54KIkxwKtiazzPESZw/glRPLA/yleJ90Aj2hUq+DGEJ7Caxu6rtweT6fH8dwN/wz8wCjd+fq15ABVnl8oCgRELUYWisZwYby1mKJ7qlC/ICEnOXBwy7rGhAGSF3ehYBcIm2t/d6AUR/+W",
      "TimestampNanos": 1675454352913804800,
      "NewMessageType": 1,
      "NewMessageOperation": 0
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {},
    "Signature": {
      "Sign": null,
      "RecoveryId": 0,
      "IsRecoverable": false
    },
    "TxnTypeJSON": 33
  },
  "TransactionHex": "0100b5dd89a30ef26d57dfd40bc6b36708a7535feaeab76ca22b58972ca3d5f488000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45f4abd52f21cb022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c452064656661756c742d6b657900000000000000000000000000000000000000000021024c402427b2dfd09f1c0bbe5c1b99fb937e34b75f6904a95560950fe19e8dc3052102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45206120737570657220636f6f6c2067726f757063686174000000000000000000002103035e1a7e9e2ac89d9dddfe4ee83049309b39ced06b83fc6da837960e42e154d57504e8cfc4ebd0f55f612e3779e0a224c702ad89acf33c4499c3f82544f2c0ff295e27dd008f6854abe0c6109ec26b1bbaaedc1e4fa7c7f1dc0dff0cfcc028ddf9fab5e400559e5f280a04442d46168ac67061bcb598a27baa50bf202127397070cbbac68401921777a16017089b6b7f77a01447ff96f5dbbcb6b69b9aa01701002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Update Group Chat Message

<mark style="color:green;">`POST`</mark> `/api/v0/update-group-chat-message`

Prepare a new message transaction to update an existing message to a group chat. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/new_message.go#L286).

#### Request Body

| Name                                                                 | Type               | Description                                                                                                                                                                                                                   |
| -------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderAccessGroupOwnerPublicKey<mark style="color:red;">\*</mark>    | String             | Public key of the user updating the message to a group chat                                                                                                                                                                   |
| SenderAccessGroupPublicKey<mark style="color:red;">\*</mark>         | String             | Public key of the access group the sender originally used for the message to the group chat                                                                                                                                   |
| SenderAccessGroupKeyName<mark style="color:red;">\*</mark>           | String             | The name of the access group the sender originally used to send the message to the group chat                                                                                                                                 |
| RecipientAccessGroupOwnerPublicKey<mark style="color:red;">\*</mark> | String             | Public key of the owner of the group to which this message was originally sent                                                                                                                                                |
| RecipientAccessGroupPublicKey<mark style="color:red;">\*</mark>      | String             | The name of the access group of the group to which this message was originally sent                                                                                                                                           |
| RecipientAccessGroupKeyName<mark style="color:red;">\*</mark>        | String             | The name of the access group of the group to which this message was originally sent                                                                                                                                           |
| EncryptedMessageText<mark style="color:red;">\*</mark>               | String             | The updated content of the message. It is recommended that this is encrypted, but it can also be provided unencrypted.                                                                                                        |
| TimestampNanosString<mark style="color:red;">\*</mark>               | String             | String version of the timestamp nanos field of the original message to the group chat. This is used to uniquely identify a message.                                                                                           |
| MinFeeRateNanosPerKB                                                 | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                      | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| ExtraData                                                            | map\[String]String | arbitrary key value data                                                                                                                                                                                                      |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "TstampNanos": 0,
  "TotalInputNanos": 99964924,
  "ChangeAmountNanos": 99964404,
  "FeeNanos": 520,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [
          0,
          181,
          221,
          137,
          163,
          14,
          242,
          109,
          87,
          223,
          212,
          11,
          198,
          179,
          103,
          8,
          167,
          83,
          95,
          234,
          234,
          183,
          108,
          162,
          43,
          88,
          151,
          44,
          163,
          213,
          244,
          136
        ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 99964404
      }
    ],
    "TxnMeta": {
      "SenderAccessGroupOwnerPublicKey": [
        2,
        170,
        61,
        200,
        210,
        153,
        234,
        30,
        73,
        20,
        222,
        102,
        73,
        78,
        211,
        225,
        110,
        218,
        154,
        13,
        101,
        113,
        157,
        82,
        60,
        26,
        154,
        3,
        203,
        249,
        246,
        12,
        69
      ],
      "SenderAccessGroupKeyName": [
        100,
        101,
        102,
        97,
        117,
        108,
        116,
        45,
        107,
        101,
        121,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "SenderAccessGroupPublicKey": [
        2,
        76,
        64,
        36,
        39,
        178,
        223,
        208,
        159,
        28,
        11,
        190,
        92,
        27,
        153,
        251,
        147,
        126,
        52,
        183,
        95,
        105,
        4,
        169,
        85,
        96,
        149,
        15,
        225,
        158,
        141,
        195,
        5
      ],
      "RecipientAccessGroupOwnerPublicKey": [
        2,
        170,
        61,
        200,
        210,
        153,
        234,
        30,
        73,
        20,
        222,
        102,
        73,
        78,
        211,
        225,
        110,
        218,
        154,
        13,
        101,
        113,
        157,
        82,
        60,
        26,
        154,
        3,
        203,
        249,
        246,
        12,
        69
      ],
      "RecipientAccessGroupKeyName": [
        97,
        32,
        115,
        117,
        112,
        101,
        114,
        32,
        99,
        111,
        111,
        108,
        32,
        103,
        114,
        111,
        117,
        112,
        99,
        104,
        97,
        116,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "RecipientAccessGroupPublicKey": [
        3,
        3,
        94,
        26,
        126,
        158,
        42,
        200,
        157,
        157,
        221,
        254,
        78,
        232,
        48,
        73,
        48,
        155,
        57,
        206,
        208,
        107,
        131,
        252,
        109,
        168,
        55,
        150,
        14,
        66,
        225,
        84,
        213
      ],
      "EncryptedText": "BOjPxOvQ9V9hLjd54KIkxwKtiazzPESZw/glRPLA/yleJ90Aj2hUq+DGEJ7Caxu6rtweT6fH8dwN/wz8wCjd+fq15ABVnl8oCgRELUYWisZwYby1mKJ7qlC/ICEnOXBwy7rGhAGSF3ehYBcIm2t/d6AUR/+W",
      "TimestampNanos": 1675454352913804800,
      "NewMessageType": 1,
      "NewMessageOperation": 1
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {},
    "Signature": {
      "Sign": null,
      "RecoveryId": 0,
      "IsRecoverable": false
    },
    "TxnTypeJSON": 33
  },
  "TransactionHex": "0100b5dd89a30ef26d57dfd40bc6b36708a7535feaeab76ca22b58972ca3d5f488000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45f4abd52f21cb022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c452064656661756c742d6b657900000000000000000000000000000000000000000021024c402427b2dfd09f1c0bbe5c1b99fb937e34b75f6904a95560950fe19e8dc3052102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45206120737570657220636f6f6c2067726f757063686174000000000000000000002103035e1a7e9e2ac89d9dddfe4ee83049309b39ced06b83fc6da837960e42e154d57504e8cfc4ebd0f55f612e3779e0a224c702ad89acf33c4499c3f82544f2c0ff295e27dd008f6854abe0c6109ec26b1bbaaedc1e4fa7c7f1dc0dff0cfcc028ddf9fab5e400559e5f280a04442d46168ac67061bcb598a27baa50bf202127397070cbbac68401921777a16017089b6b7f77a01447ff96f5dbbcb6b69b9aa01701002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## (DEPRECATED) Send Message

<mark style="color:green;">`POST`</mark> `/api/v0/send-message-stateless`

Create a Send Message transaction.

Send Message Transactions sends an encrypted message from the sender to the receiver.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/message.go#L479).

Example usages in frontend:\
\- Make Request to [Send Message Stateless](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L691) including encrypting message with identity\
\- Use SendMessage to [send a private message](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/messages-page/messages-thread-view/messages-thread-view.component.ts#L117)

#### Request Body

| Name                                                            | Type               | Description                                                                                                                                                                                                                                                                        |
| --------------------------------------------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderPublicKeyBase58Check<mark style="color:red;">\*</mark>    | String             | Public key of the user sending the message                                                                                                                                                                                                                                         |
| RecipientPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of the recipient of the message                                                                                                                                                                                                                                         |
| MessageText                                                     | String             | Unencrypted text of the message. It is recommended to encrypt the text using a shared secret and supply it in the EncryptedMessageText field instead.                                                                                                                              |
| EncryptedMessageText<mark style="color:red;">\*</mark>          | String             | Text of message encrypted with a shared secret                                                                                                                                                                                                                                     |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>          | uint64             | Rate per KB                                                                                                                                                                                                                                                                        |
| TransactionFees                                                 | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p>                                                      |
| SenderMessagingGroupKeyName                                     | String             | SenderMessagingGroupKeyName is the messaging group key name of the sender. If left empty, this endpoint will replace it with the base messaging key. If both SenderMessagingGroupKeyName and RecipientMessagingGroupKeyName are left empty, a V2 message will be constructed       |
| RecipientMessagingGroupKeyName                                  | String             | RecipientMessagingGroupKeyName is the messaging group key name of the recipient. If left empty, this endpoint will replace it with the base messaging key. If both SenderMessagingGroupKeyName and RecipientMessagingGroupKeyName are left empty, a V2 message will be constructed |
| ExtraData                                                       | map\[string]string | extra data, values must be strings. This is an arbitrary json object that can be used to add extra metadata on a message                                                                                                                                                           |

{% tabs %}
{% tab title="200: OK Successfully constructed a send message transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "TstampNanos": 1637775918769757700,
  "TotalInputNanos": 999946965,
  "ChangeAmountNanos": 999946613,
  "FeeNanos": 352,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 999946613
      }
    ],
    "TxnMeta": {
      "RecipientPublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S", // Public key (in bytes) of the recipients of the message.
      "EncryptedText": "BLBYlqu8Ns/woTNtXXi+XEbWvXYj6fe5U84VdRSPfd3gd86LENl/e03u5CChto5F+sWPRMm1/1+kuVSY0uOChLpa/9plPt/QYw0UtmTFLQTx5RWzGj5+ViE4/NB/fagQqjzusZx+gkgTzdMZU53C9jbpFEo=", // Encrypted message text bytes
      "TimestampNanos": 1637775918769757700 // Timestamp of message
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": { // Any additional keys in the ExtraData field of the request body will be included here as well.
      "V": "Ag==" // Version of message encryption used to encrypt this message
      "SenderMessagingPublicKey": "senderMessagingPublicKey", // SenderMesssagingPublicKey for v3 messages - Unintelligble bytes
      "SenderMessagingGroupKeyName": "senderMessagingGroupKeyName", // SenderGroupKeyName for v3 messages - Unintelligble bytes
      "RecipientMessagingPublicKey": "recipientMessagingPublicKey", // RecipientMesssagingPublicKey for v3 messages - Unintelligble bytes
      "RecipientMessagingGroupKeyName": "recipientMessagingGroupKeyName", // RecipientGroupKeyName for v3 messages - Unintelligble bytes
    },
    "Signature": null,
    "TxnTypeJSON": 4
  },
  "TransactionHex": "018c4bc1d70d40fa5b27d6299b9f1c6868552846bc7dbebb37c8f2c396ca3e16f6000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45f5f2e7dc03049f0102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce527404b05896abbc36cff0a1336d5d78be5c46d6bd7623e9f7b953ce1575148f7ddde077ce8b10d97f7b4deee420a1b68e45fac58f44c9b5ff5fa4b95498d2e38284ba5affda653edfd0630d14b664c52d04f1e515b31a3e7e562138fcd07f7da810aa3ceeb19c7e824813cdd319539dc2f636e9144ababcd79fd590a3dd162102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45010156010200"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## (DEPRECATED) Register Messaging Group Key

<mark style="color:green;">`POST`</mark> `/api/v0/register-messaging-group-key`

Create a Group Messaging Key for V3 messages.

Group Messaging Keys are used to power v3 messages. More info to come.

#### Request Body

| Name                                                            | Type               | Description                                                                                                                                                                                                                   |
| --------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| OwnerPublicKeyBase58Check<mark style="color:red;">\*</mark>     | String             | Public key of the account for which we want to register a messaging key                                                                                                                                                       |
| MessagingPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of the messaging group we want to register                                                                                                                                                                         |
| MessagingGroupKeyName<mark style="color:red;">\*</mark>         | String             | Name of the group key                                                                                                                                                                                                         |
| MessagingKeySignatureHex<mark style="color:red;">\*</mark>      | String             | Signature of sha256x2(MessagingPublicKeyBase58Check + MessagingGroupKeyName). Currently, the signature is only needed to register the default key                                                                             |
| ExtraData                                                       | map\[string]string | extra data, values must be strings. This is an arbitrary json object that can be used to add extra metadata on a group messaging key                                                                                          |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>          | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                 | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed a register group messaging key transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```
{
  "TstampNanos": 1637775918769757700,
  "TotalInputNanos": 999946965,
  "ChangeAmountNanos": 999946613,
  "FeeNanos": 352,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 999946613
      }
    ],
    "TxnMeta": {
      "MessagingPublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S", // Public key (in bytes) of the messaging group
      "MessagingGroupKeyName": "somekeyname", // messaging group key name in bytes
      "GroupOwnerSignature": "somebytes" // group owner signature in bytes
      "MessagingGroupMembers": [ // list of group members
        "GroupMemberPublicKey":" "publickey", // the main public key of the group chat member.
        "GroupMemberKeyName": "keyaneminbytes", // GroupMemberKeyName determines the key of the recipient that the
	                                        // encrypted key is addressed to. We allow adding recipients by their
	                                        // messaging keys. It suffices to specify the recipient's main public key
	                                        // and recipient's messaging key name for the consensus to know how to
	                                        // index the recipient. That's why we don't actually store the messaging
	                                        // public key in the MessagingGroupMember entry.
	"EncryptedKey": "encryptedbytes", // Encrypted messaging key, addressed to the recipient
      }]
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null, // Any additional keys in the ExtraData field of the request body will be included here as well.
    "Signature": null,
    "TxnTypeJSON": 23
  },
  "TransactionHex": "018c4bc1d70d40fa5b27d6299b9f1c6868552846bc7dbebb37c8f2c396ca3e16f6000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45f5f2e7dc03049f0102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce527404b05896abbc36cff0a1336d5d78be5c46d6bd7623e9f7b953ce1575148f7ddde077ce8b10d97f7b4deee420a1b68e45fac58f44c9b5ff5fa4b95498d2e38284ba5affda653edfd0630d14b664c52d04f1e515b31a3e7e562138fcd07f7da810aa3ceeb19c7e824813cdd319539dc2f636e9144ababcd79fd590a3dd162102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45010156010200"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# NFT Transactions API

Description of endpoints used to construct NFT Transactions on the DeSo blockchain

## Create NFT

<mark style="color:green;">`POST`</mark> `/api/v0/create-nft`

Create a create NFT transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.&#x20;

Create NFT transactions mints the post specified by NFTPostHashHex as an NFT.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/nft.go#L94).

Example usages in frontend:\
&#x20; \- Make request to [Create NFT](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/backend-api.service.ts#L916)\
&#x20; \- Use CreateNFT to [mint a post as an NFT](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/mint-nft-modal/mint-nft-modal.component.ts#L227)

#### Request Body

| Name                                                             | Type               | Description                                                                                                                                                                                                                                                                                        |
| ---------------------------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| NFTRoyaltyToCoinBasisPoints<mark style="color:red;">\*</mark>    | int                | Percentage (specified in basis points) of each sale that should be added to the DeSo locked on the post creator's coin                                                                                                                                                                             |
| NFTRoyaltyToCreatorBasisPoints<mark style="color:red;">\*</mark> | int                | Percentage (specified in basis points) of each sale that should be taken as a royalty to the creator of the post                                                                                                                                                                                   |
| TransactionFees                                                  | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p>                                                                      |
| HasUnlockable<mark style="color:red;">\*</mark>                  | Boolean            | When true, owner must provide unlockable text when selling this NFT                                                                                                                                                                                                                                |
| UpdaterPublicKeyBase58Check<mark style="color:red;">\*</mark>    | String             | Public key of the user creating the NFT                                                                                                                                                                                                                                                            |
| IsForSale<mark style="color:red;">\*</mark>                      | Boolean            | When true, put all serial numbers on sale                                                                                                                                                                                                                                                          |
| MinBidAmountNanos                                                | int                | Minimum bid amount allowed for all serial numbers                                                                                                                                                                                                                                                  |
| NFTPostHashHex<mark style="color:red;">\*</mark>                 | String             | Hash of the Post being minted as an NFT                                                                                                                                                                                                                                                            |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>           | uint64             | Rate per KB                                                                                                                                                                                                                                                                                        |
| NumCopies<mark style="color:red;">\*</mark>                      | int                | Number of copies to mint                                                                                                                                                                                                                                                                           |
| IsBuyNow                                                         | Boolean            | If IsForSale is false, this field is ignored. If IsBuyNow is true and IsForSale is true, all serial numbers will be put on sale and can be purchased outright at BuyNowPriceNanos. Please note that at this time, you cannot make an NFT contain an unlockable and set IsBuyNow to true.           |
| BuyNowPriceNanos                                                 | uint64             | The price at which another user can purchase this NFT without requiring an accept NFT bid transaction from the NFT owner                                                                                                                                                                           |
| AdditionalDESORoyaltiesMap                                       | map\[string]uint64 | A map of public key to basis points. Each public key specified will receive a royalty of each sale paid directly to their DeSo wallet. If a public key is mapped to 100 basis points, they will receive 1% of all sales.                                                                           |
| AdditionalCoinRoyaltiesMap                                       | map\[string]uint64 | A map of public key to basis points. Each public key specified will have a percentage of each sale added to the amount of DESO locked in their profile's creator coin. If a public key is mapped  to 100 basis points, their creator coin will have 1% of the sale price added to the DESO locked. |

{% tabs %}
{% tab title="200: OK Successfully constructed a Create NFT transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "NFTPostHashHex": "67f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0", // Post Hash Hex of post being minted as NFT
  "TotalInputNanos": 989250441,
  "ChangeAmountNanos": 989250210,
  "FeeNanos": 231,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 989250210
      }
    ],
    "TxnMeta": {
      "NFTPostHash": [103,248,14,166,144,139,147,204,169,33,162,164,158,242,104,173,55,55,86,181,186,69,175,244,224,107,247,163,31,127,32,192], // Bytes of the Post Hash that is being minted as an NFT
      "NumCopies": 1, // Number of copies of this NFT. Each has a unique serial number.
      "HasUnlockable": false, // If true, this post contains unlockable content that the seller must provide and encrypt when selling this NFT
      "IsForSale": true, // If true, bids can be submitted for any serial number of this NFT. If false, bids are not currently allowed for any serial number of this NFT.
      "MinBidAmountNanos": 106951871, // Minimum amount of DeSo (in nanos) that can be bid for any serial number.
      "NFTRoyaltyToCreatorBasisPoints": 500, // Percentage in basis points of NFT sales that will go to the creator
      "NFTRoyaltyToCoinBasisPoints": 1000 // Percentage in basis points of NFT sales that will be added to the amount locked in the NFT creator's coin
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {
      "BuyNowPriceNanos": "gIzuiRo=", // Buy Now Price in DESO nanos
      "CoinRoyaltiesMap": "AQKqPcjSmeoeSRTeZklO0+Fu2poNZXGdUjwamgPL+fYMRWQ=", // Map of public key to basis points representing royalties paid as DESO locked in creator coins
      "DESORoyaltiesMap": "AQI5exqA66CmBkRlCvE8Km/9+784gwyvw0k3p13dRLjOUvQD"// Map of public key to basis points representing royalties paid in DESO
    },
    "Signature": null,
    "TxnTypeJSON": 15
  },
  "TransactionHex": "0167f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45a285dbd7030f2b67f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0010001bfe9ff32f403e8072102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}

```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Update NFT

<mark style="color:green;">`POST`</mark> `/api/v0/update-nft`

Create an update NFT transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Update NFT transactions can put a given serial number on sale or take it off sale or update the minimum bid amount.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/nft.go#L226).

Example usages in frontend:  \
&#x20; \- Make request to [Update NFT](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L868)\
&#x20; \- Use UpdateNFT to [put an NFT on sale](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/create-nft-auction-modal/create-nft-auction-modal.component.ts#L49)\
&#x20; \- Use UpdateNFT to [close the auction on an NFT without selling](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/close-nft-auction-modal/close-nft-auction-modal.component.ts#L34)

#### Request Body

| Name                                                          | Type              | Description                                                                                                                                                                                                                                                                              |
| ------------------------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UpdaterPublicKeyBase58Check<mark style="color:red;">\*</mark> | String            | Public key of the user creating the NFT                                                                                                                                                                                                                                                  |
| NFTPostHashHex<mark style="color:red;">\*</mark>              | String            | Hash of the NFT Post being updated                                                                                                                                                                                                                                                       |
| SerialNumber<mark style="color:red;">\*</mark>                | int               | serial number to update                                                                                                                                                                                                                                                                  |
| IsForSale<mark style="color:red;">\*</mark>                   | Boolean           | When true, put this serial number on sale                                                                                                                                                                                                                                                |
| MinBidAmountNanos<mark style="color:red;">\*</mark>           | int               | Minimum bid amount allowed for this serial number                                                                                                                                                                                                                                        |
| MinFeeRteNanosPerKB<mark style="color:red;">\*</mark>         | uint64            | Rate per KB                                                                                                                                                                                                                                                                              |
| TransactionFees                                               | TransactionFee\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p>                                                            |
| IsBuyNow                                                      | Boolean           | If IsForSale is false, this field is ignored. If IsBuyNow is true and IsForSale is true, all serial numbers will be put on sale and can be purchased outright at BuyNowPriceNanos. Please note that at this time, you cannot make an NFT contain an unlockable and set IsBuyNow to true. |
| BuyNowPriceNanos                                              | uint64            | The price at which another user can purchase this NFT without requiring an accept NFT bid transaction from the NFT owner                                                                                                                                                                 |

{% tabs %}
{% tab title="200: OK Successfully constructed an Update NFT transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "NFTPostHashHex": "67f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0", // Post Hash Hex of NFT post being updated
  "SerialNumber": 1, // Serial number of NFT post that is being updated
  "TotalInputNanos": 989249984,
  "ChangeAmountNanos": 989249757,
  "FeeNanos": 227,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 989249757
      }
    ],
    "TxnMeta": {
      "NFTPostHash": [103,248,14,166,144,139,147,204,169,33,162,164,158,242,104,173,55,55,86,181,186,69,175,244,224,107,247,163,31,127,32,192], // Bytes of Post Hash being updated in this transaction
      "SerialNumber": 1, // Serial number of NFT post being updated in this transaction
      "IsForSale": true, // If true, the NFT will now be on sale. If false, the NFT will NOT be on sale
      "MinBidAmountNanos": 1000000000 // The minimum bid amount allowed on this NFT
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {
      "BuyNowPriceNanos": "gMivoCU=" // Buy Now prices in DESO nanos
    },
    "Signature": null,
    "TxnTypeJSON": 16
  },
  "TransactionHex": "01eef1a4195e53cfaa4804443c2969525494ee9511c840f9f711f5c87d9449f2b5000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45dd81dbd703102767f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c001018094ebdc032102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}

```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Create NFT Bid

<mark style="color:green;">`POST`</mark> `/api/v0/create-nft-bid`

Create an NFT bid transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

NFT Bid transactions submit a bid on an NFT. If the owner of the NFT accepts this bid - by submitting an Accept NFT Bid transaction - the bidder will send the bid amount to the owner and in return receive the NFT.

If you submit a bid on the same serial number NFT post combination, it will overwrite your previous bid. Submitting a bid with 0 as BidAmountNanos will withdraw your bid.&#x20;

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/nft.go#L364).

Example usages in frontend:\
&#x20; \- Make request to [Create NFT Bid](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L889)\
&#x20; \- Use CreateNFTBid to [submit a bid for an NFT](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/place-bid-modal/place-bid-modal.component.ts#L102)

#### Request Body

| Name                                                          | Type            | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UpdaterPublicKeyBase58Check<mark style="color:red;">\*</mark> | String          | Public key of the user submitting the bid                                                                                                                                                                                     |
| NFTPostHashHex<mark style="color:red;">\*</mark>              | String          | Hash of the NFT Post being bid on                                                                                                                                                                                             |
| SerialNumber<mark style="color:red;">\*</mark>                | int             | serial number to bid on                                                                                                                                                                                                       |
| BidAmountNanos<mark style="color:red;">\*</mark>              | int             | Amount UpdaterPublicKeyBase58Check is bidding on this serial number                                                                                                                                                           |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>        | uint64          | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                               | TransactionFee] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed an NFT Bid transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "UpdaterPublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // Public key of user submitting bid in this transaction
  "NFTPostHashHex": "67f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0", // Post Hash Hex of the NFT post being bid on
  "SerialNumber": 1, // Serial number being bid on
  "BidAmountNanos": 1000000000, // Amount bid in DeSo nanos
  "TotalInputNanos": 49578,
  "ChangeAmountNanos": 49352,
  "FeeNanos": 226,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
        "AmountNanos": 49352
      }
    ],
    "TxnMeta": {
      "NFTPostHash": [103,248,14,166,144,139,147,204,169,33,162,164,158,242,104,173,55,55,86,181,186,69,175,244,224,107,247,163,31,127,32,192], // Bytes of Post Hash that is being bid on
      "SerialNumber": 1, // Serial number being bid on
      "BidAmountNanos": 1000000000 // Amount bid in DeSo nanos
    },
    "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 18
  },
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Accept NFT Bid

<mark style="color:green;">`POST`</mark> `/api/v0/accept-nft-bid`

Create an accept NFT Bid transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Accept NFT Bid transactions accepts a bid, divides the proceeds of the bid amount among the owner, creator, and creator coin based on royalties, and updates the owner of the NFT to be the bidder selected.

Note that if you are selling an NFT that has unlockable content, you must encrypt the unlockable content and provide it.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/nft.go#L522).

Example usages in frontend:\
&#x20; \- Make request to [Accept NFT Bid](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L907) including encrypting unlockable content if applicable\
&#x20; \- Use AcceptNFTBid to [sell an NFT without unlockable content](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/sell-nft-modal/sell-nft-modal.component.ts#L65)\
&#x20; \- Use AcceptNFTBid to [sell an NFT with unlockable content](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/add-unlockable-modal/add-unlockable-modal.component.ts#L43)

#### Request Body

| Name                                                          | Type              | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UpdaterPublicKeyBase58Check<mark style="color:red;">\*</mark> | String            | Public key of the current NFT Owner                                                                                                                                                                                           |
| NFTPostHashHex<mark style="color:red;">\*</mark>              | String            | Hash of the NFT Post being sold                                                                                                                                                                                               |
| SerialNumber<mark style="color:red;">\*</mark>                | int               | serial number to being sold                                                                                                                                                                                                   |
| BidderPublicKeyBase58Check<mark style="color:red;">\*</mark>  | String            | Public key of the bidder being award the NFT                                                                                                                                                                                  |
| BidAmountNanos<mark style="color:red;">\*</mark>              | int               | Bid amount being accepted                                                                                                                                                                                                     |
| EncryptedUnlockableText                                       | String            | <p>Text encrypted with a shared secret between the current owner and the bidder<br><br>Required if NFT has unlockable content</p>                                                                                             |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>        | uint64            | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                               | TransactionFee\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed an Accept NFT Bid transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "BidderPublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // Bidder whose bid was accepted for this NFT
  "NFTPostHashHex": "67f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0", // Post Hash Hex of NFT post being sold
  "SerialNumber": 1, // Serial number being sold
  "BidAmountNanos": 1000000000, // Bid amount being accepted
  "TotalInputNanos": 989249757,
  "ChangeAmountNanos": 989249428,
  "FeeNanos": 329,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 989249428
      }
    ],
    "TxnMeta": {
      "NFTPostHash": [103,248,14,166,144,139,147,204,169,33,162,164,158,242,104,173,55,55,86,181,186,69,175,244,224,107,247,163,31,127,32,192], // Bytes of Post Hash being sold
      "SerialNumber": 1, // Serial number being sold
      "BidderPKID": [2,57,123,26,128,235,160,166,6,68,101,10,241,60,42,111,253,251,191,56,131,12,175,195,73,55,167,93,221,68,184,206,82], // Bytes of Bidder's PKID
      "BidAmountNanos": 1000000000, // Bid amount being accepted
      "UnlockableText": null, // Encrypted unlockableable text if available
      "BidderInputs": [ // Bidder Inputs used for purchasing the NFT
        {
          "TxID": [...],
          "Index": 0
        },
      ]
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 17
  },
  "TransactionHex": "0119a8f2fc3402e0501144ccf9a44d00d6045700ed9036f4770dc46e8297ee1756000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c4594ffdad703118c0167f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0012102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce528094ebdc030002b9f8047e628ff03054d8ffd0abedcd253aece89d9c97cfbcd067eaf5b8d1000a0015cf97ab3fba7c54283874c6928ff05ccf59bf0e1cb3f951cff2f1adee2bea79002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Transfer NFT

<mark style="color:green;">`POST`</mark> `/api/v0/transfer-nft`

Create a transfer NFT transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Transfer NFT transactions sends an NFT from the sender to the receiver at no cost to the receiver. NFT transfers will be pending until receiver submits an [#accept-nft-transfer](#accept-nft-transfer "mention")transaction

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/nft.go#L1399).

Example usages in [diamondapp.com](https://diamondapp.com)'s frontend:\
&#x20; \- Make request to [Transfer NFT](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/backend-api.service.ts#L1068)\
&#x20; \- Use Transfer NFT to [send NFT to another user](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/transfer-nft/transfer-nft.component.ts#L93)

#### Request Body

| Name                                                           | Type              | Description                                                                                                                                                                                                                   |
| -------------------------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderPublicKeyBase58Check<mark style="color:red;">\*</mark>   | String            | Public key of the current NFT Owner                                                                                                                                                                                           |
| ReceiverPublicKeyBase58Check<mark style="color:red;">\*</mark> | String            | Public key of the recipient of the NFT                                                                                                                                                                                        |
| NFTPostHashHex<mark style="color:red;">\*</mark>               | String            | Hash of the NFT Post being transferred                                                                                                                                                                                        |
| SerialNumber<mark style="color:red;">\*</mark>                 | int               | Serial number being transferred                                                                                                                                                                                               |
| EncryptedUnlockableText                                        | String            | <p>Text that encrypted with a shared secret between the current owner and the receiver<br><br>Required if NFT has unlockable content</p>                                                                                      |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>         | uint64            | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                | TransactionFee\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed Transfer NFT transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "SenderPublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // Public key of the user sending the NFT
  "ReceiverPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2", // Public key of the user receiving the NFT
  "NFTPostHashHex": "67f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0", // Post Hash Hex of NFT being transferred
  "SerialNumber": 1, // Serial number being transferred
  "TotalInputNanos": 49352,
  "ChangeAmountNanos": 49096,
  "FeeNanos": 256,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 3
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
        "AmountNanos": 49096
      }
    ],
    "TxnMeta": {
      "NFTPostHash": [103,248,14,166,144,139,147,204,169,33,162,164,158,242,104,173,55,55,86,181,186,69,175,244,224,107,247,163,31,127,32,192], // Bytes of Post Hash being transferred
      "SerialNumber": 1, // Serial number being transferred
      "ReceiverPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF", // Public key of user receiving NFT
      "UnlockableText": "" // Encrypted unlockable text
    },
    "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 19
  },
  "TransactionHex": "01dde32daf6f9abcd2994d671e603a13f7c5d56dd97ae31ff07d4192a884792d5f030102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52c8ff02134467f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0012102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45002102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce520000"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Accept NFT Transfer

<mark style="color:green;">`POST`</mark> `/api/v0/accept-nft-transfer`

Create an accept NFT Transfer transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Accept NFT Transfer transaction changes a transferred NFT status from pending to not pending. Since anybody can send a user an NFT, the recipient needs to accept the transfer before the NFT can appear on their profile in order to prevent users from sending spam NFTs.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/nft.go#L1557).

Example usages in [diamondapp.com](https://diamondapp.com)'s frontend:\
&#x20; \- Make request to [Accept NFT Transfer](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/backend-api.service.ts#L922)\
&#x20; \- Use AcceptNFTTransfer to [make NFT appear on your profi](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/transfer-nft-accept/transfer-nft-accept.component.ts#L56)0/accept-nft-transfer

#### Request Body

| Name                                                          | Type              | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UpdaterPublicKeyBase58Check<mark style="color:red;">\*</mark> | String            | Public key of the user accepting the NFT transfer                                                                                                                                                                             |
| NFTPostHashHex<mark style="color:red;">\*</mark>              | String            | Hash of the NFT Post for which the transfer is being accepted                                                                                                                                                                 |
| SerialNumber<mark style="color:red;">\*</mark>                | int               | serial number for which the transfer is being accepted                                                                                                                                                                        |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>        | uint64            | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                               | TransactionFee\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully construct an Accept NFT Transfer transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "UpdaterPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2", // Public key of user accepting NFT transfer
  "NFTPostHashHex": "67f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0", // Post Hash Hex of the NFT that is being accepted
  "SerialNumber": 1, // Serial Number whose transfer is being accepted
  "TotalInputNanos": 50000000,
  "ChangeAmountNanos": 49999779,
  "FeeNanos": 221,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 2
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 49999779
      }
    ],
    "TxnMeta": {
      "NFTPostHash": [103,248,14,166,144,139,147,204,169,33,162,164,158,242,104,173,55,55,86,181,186,69,175,244,224,107,247,163,31,127,32,192], // Bytes of the Post Hash of the NFT whose transferred is being accepted
      "SerialNumber": 1 // Serial Number whose transfer is being accepted
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 20
  },
  "TransactionHex": "01dde32daf6f9abcd2994d671e603a13f7c5d56dd97ae31ff07d4192a884792d5f020102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45a3dfeb17142167f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0012102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Burn NFT

<mark style="color:green;">`POST`</mark> `/api/v0/burn-nft`

Create a Burn NFT transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

NFT Burn transactions burns the NFT, meaning that no user can ever own that Post hash-serial number combination.

Endpoint implementation in backend.

Example usages in frontend:\
&#x20; \- Make request to [Burn NFT](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/backend-api.service.ts#L906)\
&#x20; \- Use BurnNFT to [burn the NFT ](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/nft-burn/nft-burn.component.ts#L89)

#### Request Body

| Name                                                          | Type              | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UpdaterPublicKeyBase58Check<mark style="color:red;">\*</mark> | String            | Public key of the user burning the NFT transfer                                                                                                                                                                               |
| NFTPostHashHex<mark style="color:red;">\*</mark>              | String            | Hash of the NFT Post that is being burnt                                                                                                                                                                                      |
| SerialNumber<mark style="color:red;">\*</mark>                | int               | serial number that is being burnt                                                                                                                                                                                             |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>        | uint64            | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                               | TransactionFee\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed Burn NFT transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "UpdaterPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2", // Public key of user burning the NFT
  "NFTPostHashHex": "67f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0", // Post Hash Hex of NFT being burned
  "SerialNumber": 1, // Serial number being burned
  "TotalInputNanos": 49999779,
  "ChangeAmountNanos": 49999558,
  "FeeNanos": 221,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 49999558
      }
    ],
    "TxnMeta": {
      "NFTPostHash": [103,248,14,166,144,139,147,204,169,33,162,164,158,242,104,173,55,55,86,181,186,69,175,244,224,107,247,163,31,127,32,192], // Bytes of Post Hash being burned 
      "SerialNumber": 1 // Serial number being burned
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 21
  },
  "TransactionHex": "0161b49620c72975d8397836c6b28981a0257d846e28ee74b296264bf1e2109036000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45c6ddeb17152167f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0012102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# Financial Transactions API

Description of endpoints used to construct Financial Transactions on the DeSo blockchain

## Send DeSo

<mark style="color:green;">`POST`</mark> `/api/v0/send-deso`

Create a Basic transfer transaction. Basic transfer transactions send DeSo from one used to another. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

A Basic Transfer transaction sends DeSo from the sender to the receiver.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L905).

Example usage in frontend:\
&#x20; \- Make request to Send DeSo to get [a preview of the transaction.](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L905)\
&#x20; \- Make request to Send DeSo and [sign+submit the transaction.](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L667)\
&#x20; \- Use SendDeSo to [transfer DeSo to another user.](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/transfer-deso/transfer-deso.component.ts#L165)

#### Request Body

| Name                                                           | Type            | Description                                                                                                                                                                                                                   |
| -------------------------------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderPublicKeyBase58Check<mark style="color:red;">\*</mark>   | String          | Public key of the sender                                                                                                                                                                                                      |
| RecipientPublicKeyOrUsername<mark style="color:red;">\*</mark> | String          | Public key or Username of the recipient                                                                                                                                                                                       |
| AmountNanos<mark style="color:red;">\*</mark>                  | int64           | transaction amount in nanos - If less than 0, this will create a max spend transaction that will send all funds from Sender to Receiver                                                                                       |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>         | uint64          | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                | TransactionFee] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed Send DeSo transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "TotalInputNanos": 1999946613,
  "SpendAmountNanos": 1000000000,
  "ChangeAmountNanos": 999946354,
  "FeeNanos": 259,
  "TransactionIDBase58Check": "CbUyAcAiR5C626pSXQ1KCHWxo55FiSsBS66GELxVPPJMT2Q4yjFTA",
  "Transaction": {
    "TxInputs": [ 
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
        "AmountNanos": 1000000000
      },
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 999946354
      }
    ],
    "TxnMeta": {},
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 2
  },
  "TransactionHex": "025051b0eeda78885641a2340f57b908f475d84ce3b8ce2507815c89e857ef1cce0006caf6e4d44a8575fe235d7d3ffdb1020485526118d3379f5a993a31f5a2823f000202397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce528094ebdc0302aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45f2f0e7dc0302002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000",
  "TxnHashHex": "df850aef107687e36034e3d298da341fc747d4a663e0a5e98fe3ce05cc10b4be"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Buy Or Sell Creator Coin

<mark style="color:green;">`POST`</mark> `/api/v0/buy-or-sell-creator-coin`

Create a buy/sell creator coin transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.&#x20;

A buy creator coin transaction locks DeSo in the creator coin of a creator and in return gives the purchaser creator coins.&#x20;

A sell creator coin transaction unlocks an amount of DeSo commensurate with the amount of creator coins sold.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L1602).

Example usages in frontend:\
&#x20; \- Make request to [Buy Or Sell Creator Coin](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1485)\
&#x20; \- Use BuyOrSellCreatorCoin to get a [preview of purchase/sale of creator coins](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/trade-creator-page/trade-creator-form/trade-creator-form.component.ts#L190)\
&#x20; \- Use BuyOrSellCreatorCoin to [buy or sell creator coins](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/trade-creator-page/trade-creator-preview/trade-creator-preview.component.ts#L89)

#### Request Body

| Name                                                          | Type             | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| MinCreatorCoinExpectedNanos                                   | uint64           | <p>Minimum amount of Creator Coins expected when buying creator coins<br><br>only required for buy transactions</p>                                                                                                           |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>        | uint64           | Rate per KB                                                                                                                                                                                                                   |
| CreatorCoinToSellNanos<mark style="color:red;">\*</mark>      | uint64           | <p>Amount of Creator Coin to sell<br><br>only required for sell transactions</p>                                                                                                                                              |
| TransactionFees                                               | TrasactionFee\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| CreatorPublicKeyBase58Check<mark style="color:red;">\*</mark> | String           | Public key of creator whose coin is being purchased                                                                                                                                                                           |
| DeSoToAddNanos<mark style="color:red;">\*</mark>              | uint64           | deprecated                                                                                                                                                                                                                    |
| OperationType<mark style="color:red;">\*</mark>               | String           | "buy" or "sell"                                                                                                                                                                                                               |
| MinDeSoExpectedNanos                                          | uint64           | <p>Minimum DeSo expected to be received when selling creator coins<br><br>only required for sell transactions</p>                                                                                                             |
| DeSoToSellNanos<mark style="color:red;">\*</mark>             | uint64           | <p>Amount of DeSo to spend purchasing creator coins<br><br>only required for buy transactions</p>                                                                                                                             |
| UpdaterPublicKeyBase58Check<mark style="color:red;">\*</mark> | String           | Public key of user purchasing/selling creator coins                                                                                                                                                                           |
| InTutorial                                                    | Boolean          | When true, perform additional checks to ensure user is at the correct point in the tutorial to execute this buy/sell creator coin transaction                                                                                 |

{% tabs %}
{% tab title="200: OK Successfully construct Buy Creator Coin transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "ExpectedDeSoReturnedNanos": 0, // Expected amount of DeSo received from the sale. Will always be 0 for buys.
  "ExpectedCreatorCoinReturnedNanos": 1200, // Expected amount of creator coins received from the purchase. Will always be 0 for sales.
  "FounderRewardGeneratedNanos": 9999664686, // Founders reward generated from this purchase. Will always be 0 for sales.
  "SpendAmountNanos": 1000000000,
  "TotalInputNanos": 1933081867,
  "ChangeAmountNanos": 933081602,
  "FeeNanos": 265,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [... ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 933081602
      }
    ],
    "TxnMeta": {
      "ProfilePublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF", // Public key of the creator whose coin was purchased in this transaction
      "OperationType": 0, // 0 means buy, 1 means sell
      "DeSoToSellNanos": 1000000000, // Amount of DeSo used to purchase creator coins in this transaction
      "CreatorCoinToSellNanos": 0, // Amount of creator coins sold in this transaction
      "DeSoToAddNanos": 0, // not in use - ignore
      "MinDeSoExpectedNanos": 0, // Minimum DeSo expected from a creator coin sale. This will always be 0 for buys.
      "MinCreatorCoinExpectedNanos": 1000 // Minimum amount of creator coins expected from this purchase. This will always be 0 for sales.
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 11
  },
  "TransactionHex": "02acc5b6f137be6a9b49fa1e0b20d0b6c5f2a76618628e1cd34fe8dbb198b627f1001ba3390ffb4817f3d5993ef39fd2fc4cfd75312ba67a7ce2f1d083efa0df2e5e000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c4582e4f6bc030b2c2102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45008094ebdc03000000002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000",
  "TxnHashHex": "69f08986184d99833c40d794d3fdd8861c0be602f15e3021ed771e49c6f7771c"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}

{% tab title="200: OK Successfully constructed Sell Creator Coin transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "ExpectedDeSoReturnedNanos": 270953971, // Expected amount of DeSo received from the sale. Will always be 0 for buys.
  "ExpectedCreatorCoinReturnedNanos": 0, // Expected amount of creator coins received from the purchase. Will always be 0 for sales.
  "FounderRewardGeneratedNanos": 0, // Founder reward generated from this transaction. Will always be 0 for sales.
  "SpendAmountNanos": 0,
  "TotalInputNanos": 933081602,
  "ChangeAmountNanos": 933081367,
  "FeeNanos": 235,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 933081367
      }
    ],
    "TxnMeta": {
      "ProfilePublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF", // Public key of the creator whose coin was purchased in this transaction
      "OperationType": 1, // 0 means buy, 1 means sell
      "DeSoToSellNanos": 0, // Amount of DeSo used to purchase creator coins in this transaction
      "CreatorCoinToSellNanos": 1000000000, // Amount of creator coins sold in this transaction
      "DeSoToAddNanos": 0, // Not in use - ignore.
      "MinDeSoExpectedNanos": 203215478, // Minimum DeSo expected from a creator coin sale. This will always be 0 for buys.
      "MinCreatorCoinExpectedNanos": 0 // Minimum amount of creator coins expected from this purchase. This will always be 0 for sales.
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 11
  },
  "TransactionHex": "013a58bb26ece8a6abb8f81d4d63359cd42a1602ffc0b99588d70f5278c3e2cb34000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c4597e2f6bc030b2f2102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c4501008094ebdc0300f6a4f360002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000",
  "TxnHashHex": "c4a8163660bc46f5d6b51f55d0b6b6070d72939eeea13ccae422d78cb255859b"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}
{% endtabs %}

## Transfer Creator Coin

<mark style="color:green;">`POST`</mark> `/api/v0/transfer-creator-coin`

Create a transfer creator coin transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.&#x20;

Transfer creator coin transactions sends creator coins owned by the sender to the receiver.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L1860).

Example usages in frontend:\
&#x20; \- Make request to [Transfer Creator Coin](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1543)\
&#x20; \- Use TransferCreatorCoin to get a [preview of a creator coin transfer transaction](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/trade-creator-page/trade-creator-form/trade-creator-form.component.ts#L152).\
&#x20; \- Use TransferCreatorCoin to [construct, sign, and submit a creator coin transfer transaction](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/trade-creator-page/trade-creator-preview/trade-creator-preview.component.ts#L167).

#### Request Body

| Name                                                                     | Type             | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------------------ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderPublicKeyBase58Check<mark style="color:red;">\*</mark>             | String           | Public key of user sending creator coins                                                                                                                                                                                      |
| CreatorPublicKeyBase58Check<mark style="color:red;">\*</mark>            | String           | Public key of creator whose coins will be sent                                                                                                                                                                                |
| ReceiverUsernameOrPublicKeyBase58Check<mark style="color:red;">\*</mark> | String           | username or public key of user who will receive creator coins                                                                                                                                                                 |
| CreatorCoinToTransferNanos<mark style="color:red;">\*</mark>             | uint64           | Amount of Creator Coin to transfer                                                                                                                                                                                            |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>                   | uint64           | Rate per KB                                                                                                                                                                                                                   |
| TrasactionFees                                                           | TrasactionFee\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed Transfer Creator Coin transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "SpendAmountNanos": 0,
  "TotalInputNanos": 989250936,
  "ChangeAmountNanos": 989250675,
  "FeeNanos": 261,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 989250675
      }
    ],
    "TxnMeta": {
      "ProfilePublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF", // Public key of the creator whose coin is being transferred in this transaction
      "CreatorCoinToTransferNanos": 1000000000, // Amount of Creator coins being transferred (in nanos)
      "ReceiverPublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S" // Public key of the recipient of the creator coin transfer
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": null,
    "Signature": null,
    "TxnTypeJSON": 14
  },
  "TransactionHex": "01f2816e264f381cf153299e0c3cc894ab67687e83b79e55996bdb1c44280aed1d000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45f388dbd7030e492102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c458094ebdc032102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce522102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000",
  "TxnHashHex": "a0e90d5786367855ea2960cd4d8cc3ad81a73c056c7ee62a637ab17aa01320fe"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# Derived Keys Transaction API

Description of endpoints used to construct Derived Key Transactions on the DeSo blockchain

## Authorize Derived Key

<mark style="color:green;">`POST`</mark> `/api/v0/authorize-derived-key`

Create an authorize derived key transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Authorize derived key transactions allows another public key to submit transaction on behalf of the owner public key.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/954490fee2319072a9d6af710e3a3dd21bfc4f2d/routes/transaction.go#L2646).

#### Request Body

| Name                                                          | Type               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| OwnerPublicKeyBase58Check<mark style="color:red;">\*</mark>   | String             | Public key of the derived key owner                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| DerivedPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | The derived public key                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ExpirationBlock<mark style="color:red;">\*</mark>             | uint64             | Height of block after which this derived key will no longer work.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| AccessSignature<mark style="color:red;">\*</mark>             | String             | The signature of hash(derived key + expiration block) made by the owner.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| DeleteKey<mark style="color:red;">\*</mark>                   | Boolean            | The intended operation on the derived key. If true, this derived key will no longer be valid.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>        | uint64             | Rate per KB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| TransactionFees                                               | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| TransactionSpendingLimitHex<mark style="color:red;">\*</mark> | String             | <p>Hex string representing a TransactionSpendingLimit struct that will be merged with the TransactionSpendingLimitTracker for this derived key. We require this be sent as a hex in order toguarantee that the AccessHash computed from this value is consistent with what the user is requesting.</p><p>The TransactionSpendingLimit is an object defining the permissions of this derived key. Derived key will be restricted to certain transaction types and can only spend up to the specified amount of DESO. See the section on <a data-mention href="/pages/pK92RdbTZJy2NdpI52Cc#transactionspendinglimitresponse">/pages/pK92RdbTZJy2NdpI52Cc#transactionspendinglimitresponse</a> for more details.      </p> |
| Memo                                                          | String             | Memo to describe the purpose of this derived key                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| AppName                                                       | String             | App requested this derived key. This is used if a memo is not provided so a user can remember which app has access with this derived key.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| ExtraData                                                     | map\[string]string | extra data, values must be strings. This is an arbitrary json object that can be used to add extra metadata on a derived key                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| DerivedKeySignature                                           | Boolean            | Set to true if you intend to sign this transaction with the derived public key instead of the owner public key. This will add the DerivedPublicKey to ExtraData                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |

{% tabs %}
{% tab title="200: OK Successfully constructed Authorize Derived Key transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "TotalInputNanos": 49999779,
  "ChangeAmountNanos": 49999558,
  "FeeNanos": 221,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [...],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 49999558
      }
    ],
    "TxnMeta": {
      "DerivedPublicKey": [1,2,3, ...], // Bytes of the Derived public key 
      "ExpirationBlock": 91273 // Block height at which this derived key expires
      "AccessSignature": [23, 34, 45, ...], // Bytes access signature. This is the signed hash of (derivedPublicKey + expirationBlock) made with the ownerPublicKey. Signature is in DER format.
      "OperationType": 1, // 1 means this transaction makes the derived public key valid. 0 means this transaction makes the derived public key invalid.
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": { Any additional keys in the ExtraData field of the request body will be included here as well.
      "DerivedKeyMemo": "Nzg3ODc5Nzk3YTdh", // bytes of the memo for this derived key
      "TransactionSpendingLimit": "gNDbw/QCAgIKFgEAAAA=", // bytes of the transaction spending limits for this derived key
    },
    "Signature": null,
    "TxnTypeJSON": 22
  },
  "TransactionHex": "0161b49620c72975d8397836c6b28981a0257d846e28ee74b296264bf1e2109036000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45c6ddeb17152167f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0012102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# DeSo Tokens Transactions API

Description of endpoints used to construct DAO Transactions on the DeSo blockchain

<mark style="color:red;">Note: "DAO Coins" are now referred to as "</mark><mark style="color:red;">**DeSo Tokens**</mark><mark style="color:red;">" in all public-facing documentation, but the code and API have not yet been updated to reflect this change.</mark><br>

## Create DeSo Token (DAO Coin)

<mark style="color:green;">`POST`</mark> `/api/v0/dao-coin`

Create a DeSo Token transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.&#x20;

A `mint` operation creates new DeSo Tokens

A `burn` operation destroys DeSo Tokens

An `update_transfer_restriction_status` operation updates the restrictions on transferring a DeSo Tokens

A `disable_minting` operation prevents minting of any future DeSo Tokens

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/transaction.go#L2271).

Example usages in frontend:\
&#x20; \- Make request to [DeSo Tokens](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/backend-api.service.ts#L1739)\
&#x20; \- Use DeSo Tokens to [mint DeSo Tokens](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/dao-coins/dao-coins.component.ts#L214)\
&#x20; \- Use DeSo Tokens to [burn DeSo Tokens](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/dao-coins/dao-coins.component.ts#L333)\
&#x20; \- Use DeSo Tokens to [update transfer restriction status](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/dao-coins/dao-coins.component.ts#L292)\
&#x20; \- Use DeSo Tokens to [disable minting](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/dao-coins/dao-coins.component.ts#L257)

#### Request Body

| Name                                                                    | Type               | Description                                                                                                                                                                                                                                                                                                                          |
| ----------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| UpdaterPublicKeyBase58Check<mark style="color:red;">\*</mark>           | String             | Public key performing the DeSo Token operation                                                                                                                                                                                                                                                                                       |
| ProfilePublicKeyBase58CheckOrUsername<mark style="color:red;">\*</mark> | String             | Public key  or username of the creator of the Token on whose DeSo Token Updater is operating                                                                                                                                                                                                                                         |
| OperationType<mark style="color:red;">\*</mark>                         | String             | Type of DeSo Token operation being perform. Must be `mint`, `burn`, `update_transfer_restriction_status`, or `disable_minting`                                                                                                                                                                                                       |
| CoinsToMintNanos                                                        | String             | <p>Hex string representing the number of DeSo Tokens in this operation.</p><p></p><p><strong>Required if OperationType is <code>mint</code></strong></p>                                                                                                                                                                             |
| CoinsToBurnNanos                                                        | String             | <p>Hex string representing the number of DeSo Tokens burned in this operation.</p><p></p><p><strong>Required if OperationType is <code>burn</code></strong></p>                                                                                                                                                                      |
| TransferRestrictionStatus                                               | String             | <p>String representing the new transfer restriction status. Valid values are <code>unrestricted</code>, <code>profile\_owner\_only</code>, <code>dao\_members\_only</code>, <code>permanently\_unrestricted</code></p><p></p><p><strong>Required if OperationType is <code>update\_transfer\_restriction\_status</code></strong></p> |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>                  | uint64             | Rate per KB                                                                                                                                                                                                                                                                                                                          |
| TransactionFees                                                         | TransactionFees\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p>                                                                                                        |

{% tabs %}
{% tab title="200: OK Successfully constructed a DeSo Token transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
    "TotalInputNanos": 799994621,
    "ChangeAmountNanos": 799994391,
    "FeeNanos": 230,
    "Transaction": {
      "TxInputs": [
        {
          "TxID": [... ],
          "Index": 0
        }
      ],
      "TxOutputs": [
        {
          "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
          "AmountNanos": 799994391
        }
      ],
      "TxnMeta": {
        "ProfilePublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S", // Public key of the DAO coin creator
        "OperationType": 0, // Integer representing operation type. 0 is mint, 1 is burn, 2 is update transfer restriction status, 3 is disable minting
        "CoinsToMintNanos": "0x3b9aca00", // Hex string representing the number of nanos be minted in this transaction. Only set if operation type is 0.
        "CoinsToBurnNanos": "0x0", // Hex string representing the number of nanos being burned in this transaction. Only set if operation type is 1.
        "TransferRestrictionStatus": 0 // Integer representing the transfer restriction status being set in this transaction. Only set if operation type is 2.is 
      },
      "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
      "ExtraData": null,
      "Signature": null,
      "TxnTypeJSON": 24
    },
    "TransactionHex": "01c64eebdaf08d50f8bea79e6f2004b6b7b826fb3245f044271c6c8b6708e76a68000102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce5297e4bbfd02182a2102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce5200043b9aca0000002102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce520000",
    "TxnHashHex": "88595b14baf461bdc04020bd705c8e7f08d9bacef88cbaedefcae6328852292e"
}
```

{% endtab %}

{% tab title=" Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Transfer DeSo Token (DAO Coin)

<mark style="color:green;">`POST`</mark> `/api/v0/transfer-dao-coin`

Create a transfer DeSo Token transaction. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.&#x20;

Transfer DeSo Token coin transactions sends DeSo Token owned by the sender to the receiver.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/transaction.go#L2448).

Example usages in frontend:\
&#x20; \- Make request to [Transfer DeSo Token](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/backend-api.service.ts#L1761)\
&#x20; \- Use TransferDAOCoin to [construct, sign, and submit a DeSo Token transfer transaction](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/dao-coins/transfer-dao-coin-modal/transfer-dao-coin-modal.component.ts#L67).

#### Request Body

| Name                                                                     | Type               | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------------------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SenderPublicKeyBase58Check<mark style="color:red;">\*</mark>             | String             | Public key of the user sending DeSo Token                                                                                                                                                                                     |
| ProfilePublicKeyBase58CheckOrUsername<mark style="color:red;">\*</mark>  | String             | Public key of the creator whose DeSo Token will be sent in this transaction                                                                                                                                                   |
| ReceiverPublicKeyBase58CheckOrUsername<mark style="color:red;">\*</mark> | String             | Public key of the recipient                                                                                                                                                                                                   |
| DAOCoinToTransferNanos<mark style="color:red;">\*</mark>                 | String             | Hex string representing the amount of DeSo Tokens to transfer in this transaction                                                                                                                                             |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>                   | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                          | TransactionFees\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed a DeSo Token transfer transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
    "SpendAmountNanos": 0,
    "TotalInputNanos": 799994391,
    "ChangeAmountNanos": 799994130,
    "FeeNanos": 261,
    "Transaction": {
      "TxInputs": [
        {
          "TxID": [... ],
          "Index": 0
        }
      ],
      "TxOutputs": [
        {
          "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
          "AmountNanos": 799994130
        }
      ],
      "TxnMeta": {
        "ProfilePublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S", // Public key of the DAO coin creator whose DAO coin you wish to transfer
        "DAOCoinToTransferNanos": "0x3b9aca00", // Hex string representing the number of DAO coins being transferred
        "ReceiverPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF" // Public key of recipient
      },
      "PublicKey": "Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
      "ExtraData": null,
      "Signature": null,
      "TxnTypeJSON": 25
    },
    "TransactionHex": "015b9860bf3343449c19ff8227c0d932e4f996a4710ea0b6de268411137ed8e7cf000102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce5292e2bbfd0219492102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52043b9aca002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c452102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce520000",
    "TxnHashHex": "7be4ac172d789b25657a12e109ec5502301483af27f0a394fff030622819a2f3"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Create DeSo Token (DAO Coin) Limit Order

<mark style="color:green;">`POST`</mark> `/api/v0/create-doa-coin-limit-order`

Create a new limit order to trade DeSo Tokens. The transaction needs to be signed and submitted through `api/v0/submit-transaction` before the order can be placed on the book or the coins are traded.

DeSo Tokens can be traded on an on-chain order book exchange. There are two types of markets where DeSo Tokens can be traded on the exchange: 1) markets where a DeSo Token is traded for $DESO, and 2) markets where a DeSo Token is traded for another DeSo Token.

This endpoint allows the creation of limit orders for either type of market.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/0af8093227b219de31487ac129e799fee61e39ef/routes/transaction.go#L2582)

#### Request Body

| Name                                                                                  | Type               | Description                                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check<mark style="color:red;">\*</mark>                      | String             | Public key of the user creating the limit order                                                                                                                                                                                                                                                                                                                                                             |
| BuyingDAOCoinCreatorPublicKeyBase58CheckOrUsername<mark style="color:red;">\*</mark>  | String             | <p>Public key or username of the creator of a profile, whose DeSo Token is being bought.</p><p></p><p>If the order is selling a DeSo Token for $DESO, then this parameter needs to be an empty string.</p>                                                                                                                                                                                                  |
| SellingDAOCoinCreatorPublicKeyBase58CheckOrUsername<mark style="color:red;">\*</mark> | String             | <p>Public key or username of the creator of a profile whose DeSo Token is being sold. </p><p></p><p>If the order is buying a DeSo Token with $DESO, then this parameter needs to be an empty string.</p>                                                                                                                                                                                                    |
| ExchangeRateCoinsToSellPerCoinToBuy<mark style="color:red;">\*</mark>                 | float64            | The desired exchange rate for the coin being sold relative to the coin being bought. The real exchange rate used to fill this order will be equal to or better than the exchange rate provided here, always in the favor of the transactor.                                                                                                                                                                 |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>                                | uint64             | Rate per KB                                                                                                                                                                                                                                                                                                                                                                                                 |
| TransactionFees                                                                       | TransactionFees\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p>                                                                                                                                                                               |
| QuantityToFill<mark style="color:red;">\*</mark>                                      | float64            | <p>The desired quantity of coins to buy or sell. This is denominated in number of coins (not nanos) and can have fractional values.</p><p></p><p>For example, if you wanted to fill an order of 1 DESO, you would specify 1 here, not 10^9.</p>                                                                                                                                                             |
| OperationType<mark style="color:red;">\*</mark>                                       | string             | <p>Supports values "BID" or "ASK".</p><p></p><p>"BID" signifies that this order wants to buy <code>QuantityToFill</code> total coins of the <code>BuyingDAOCoinCreatorPublicKeyBase58CheckOrUsername</code> coin.</p><p></p><p>"ASK" signifies that this limit order wants to sell <code>QuantityToFill</code> total coins of the <code>BuyingDAOCoinCreatorPublicKeyBase58CheckOrUsername</code> coin.</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed a DeSo Token coin limit order transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
   "ChangeAmountNanos":199979890,
   "FeeNanos":336,
   "SpendAmountNanos":0,
   "TotalInputNanos":199980226,
   "Transaction":{
      "ExtraData":null,
      "PublicKey":"Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
      "Signature":null,
      "TxInputs":[
         {
            "Index":0,
            "TxID":[...]
         }
      ],
      "TxOutputs":[
         {
            "AmountNanos":199979890,
            "PublicKey":"Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S"
         }
      ],
      "TxnMeta":{
         "BidderInputs":null,
         "BuyingDAOCoinCreatorPublicKey":[...] // binary encoding of the coin being bought,
         "CancelOrderID":null,
         "FeeNanos":336,
         "OperationType":2, // integer value representing operation type; ASK = 1, BID = 2
         "QuantityToFillInBaseUnits":"0x12a05f200", // hex encoding of the quantity to filled
         "ScaledExchangeRateCoinsToSellPerCoinToBuy":"0xe1b1e5f90f944d6e1c9e66c000000000", // hex encoding of the exchange rate
         "SellingDAOCoinCreatorPublicKey":[... ] // binary encoding of the coin being sold
      },
      "TxnTypeJSON":26
   },
   "TransactionHex":"0133f5d223856b61216c68433257f9ed851c5e8f15c325d29ac38661b999484adb000102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52f2e6ad5f1a8b012102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52210000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000e1b1e5f90f944d6e1c9e66c00000000020000000000000000000000000000000000000000000000000000000012a05f200020000d0022102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce520000",
   "TxnHashHex":"8e89a8edab106eb81046fac36de8119c8ce325490ba2549c84e8d77e113572f2"
}

```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    "error": "..." // error message
}
```

{% endtab %}

{% tab title="500: Internal Server Error " %}

```javascript
{
    "error": "..." // error message
}
```

{% endtab %}
{% endtabs %}

## Cancel DeSo Token (DAO Coin) Limit Order

<mark style="color:green;">`POST`</mark> `/api/v0/cancel-dao-coin-limit-order`

Cancel an open limit order to trade DeSo Token. The transaction needs to be signed and submitted through `api/v0/submit-transaction` before the order is cancelled.&#x20;

This endpoint allows a transactor to cancel a limit order they had previously created. The request will only succeed if the order is still open, and has not been completely filled or previously cancelled.

See [DeSo Tokens Endpoints](/deso-backend/api/dao-endpoints#gets-all-open-limit-orders-created-by-a-transactor) for how to retrieve all open orders created by a transactor.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/0af8093227b219de31487ac129e799fee61e39ef/routes/transaction.go#L2729)

#### Request Body

| Name                                                             | Type               | Description                                                                                                                                                                                                                   |
| ---------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of the user who created the the limit order being cancelled                                                                                                                                                        |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>           | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                  | TransactionFees\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| CancelOrderID<mark style="color:red;">\*</mark>                  | string             | Unique order identifier for the original limit order to cancel. OrderID is also equivalent to the base64 transaction hash hex of the transaction that created the limit order.                                                |

{% tabs %}
{% tab title="200: OK Successfully constructed a transaction to cancel an open DAO coin limit order" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
   "SpendAmountNanos":0,
   "TotalInputNanos":199978801,
   "ChangeAmountNanos":199978564,
   "FeeNanos":237,
   "Transaction":{
      "TxInputs":[
         {
            "TxID":[...],
            "Index":0
         }
      ],
      "TxOutputs":[
         {
            "PublicKey":"Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
            "AmountNanos":199978564
         }
      ],
      "TxnMeta":{
         "BuyingDAOCoinCreatorPublicKey":null,
         "SellingDAOCoinCreatorPublicKey":null,
         "ScaledExchangeRateCoinsToSellPerCoinToBuy":null,
         "QuantityToFillInBaseUnits":null,
         "OperationType":0,
         "CancelOrderID":[...], // binary encoding for the order id for the limit order being cancelled
         "BidderInputs":null,
         "FeeNanos":237
      },
      "PublicKey":"Ajl7GoDroKYGRGUK8Twqb/37vziDDK/DSTenXd1EuM5S",
      "ExtraData":null,
      "Signature":null,
      "TxnTypeJSON":26
   },
   "TransactionHex":"012f6fcc9bf20ae44b0fa6e399bedeafbc2080d6e8c8e89a58db5b28730b3ad4f4000102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52c4dcad5f1a2900000000002033f5d223856b61216c68433257f9ed851c5e8f15c325d29ac38661b999484adb00ed012102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce520000",
   "TxnHashHex":"b3bec41bc59852277808459efbdc1509c08347f9e381459e886e14235a661ae8"
}

```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    "error": "..." // error message
}
```

{% endtab %}

{% tab title="500: Internal Server Error " %}

```javascript
{
    "error": "..." // error message
}
```

{% endtab %}
{% endtabs %}


# Associations Transactions API

Description of endpoints to construct Associations Transactions on the DeSo blockchain

### User Associations

## Create user association

<mark style="color:green;">`POST`</mark> `/api/v0/user-associations/create`

Creates a create user association transaction. The transaction needs to be signed and submitted through `/api/v0/submit-transaction` before changes come into effect.

Implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/associations.go#L152)

#### Request Body

| Name                                                             | Type               | Description                                                                                                                                                                                                                   |
| ---------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | The public key of the user creating the transaction                                                                                                                                                                           |
| TargetUserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | The public key of the user to which the association is referencing                                                                                                                                                            |
| AppPublicKeyBase58Check                                          | String             | The public key of the application on which the association is being created                                                                                                                                                   |
| AssociationType<mark style="color:red;">\*</mark>                | String             | The association type                                                                                                                                                                                                          |
| AssociationValue<mark style="color:red;">\*</mark>               | String             | The association value                                                                                                                                                                                                         |
| ExtraData                                                        | map\[String]String | Any additional arbitrary key-value data to store with the association                                                                                                                                                         |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>           | uint64             | The minimum fee rate (in nanos) per kb                                                                                                                                                                                        |
| TransactionFees                                                  | \[]TransactionFee  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed a create user association transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "SpendAmountNanos": 0,
    "TotalInputNanos": 999999594,
    "ChangeAmountNanos": 999999032,
    "FeeNanos": 562,
    "Transaction": {
        "TxInputs": [
            {
                "TxID": [
                    53,
                    195,
                    47,
                    166,
                    22,
                    216,
                    106,
                    179,
                    186,
                    225,
                    130,
                    110,
                    104,
                    152,
                    74,
                    215,
                    74,
                    183,
                    183,
                    53,
                    148,
                    68,
                    5,
                    24,
                    140,
                    59,
                    26,
                    222,
                    129,
                    155,
                    71,
                    154
                ],
                "Index": 0
            }
        ],
        "TxOutputs": [
            {
                "PublicKey": "A0LZQ7jbqTpM4puFhHnGfx5PERDuy+H4PcAbRV64sSOz",
                "AmountNanos": 999999032
            }
        ],
        "TxnMeta": {
            "TargetUserPublicKey": [
                3,
                95,
                255,
                160,
                105,
                4,
                12,
                4,
                60,
                209,
                243,
                177,
                97,
                96,
                27,
                254,
                116,
                12,
                121,
                196,
                61,
                110,
                188,
                220,
                197,
                18,
                109,
                28,
                59,
                216,
                172,
                68,
                224
            ],
            "AppPublicKey": [
                2,
                88,
                191,
                20,
                43,
                67,
                244,
                2,
                20,
                110,
                45,
                7,
                44,
                158,
                243,
                19,
                216,
                99,
                248,
                244,
                90,
                149,
                247,
                213,
                172,
                230,
                29,
                245,
                127,
                216,
                190,
                252,
                93
            ],
            "AssociationType": "RU5ET1JTRU1FTlQ=",
            "AssociationValue": "U1FM"
        },
        "PublicKey": "A0LZQ7jbqTpM4puFhHnGfx5PERDuy+H4PcAbRV64sSOz",
        "ExtraData": {
            "PeerID": "QQ=="
        },
        "Signature": {
            "Sign": null,
            "RecoveryId": 0,
            "IsRecoverable": false
        },
        "TxnTypeJSON": 27
    },
    "TransactionHex": "0135c32fa616d86ab3bae1826e68984ad74ab7b735944405188c3b1ade819b479a00010342d943b8dba93a4ce29b858479c67f1e4f1110eecbe1f83dc01b455eb8b123b3b88cebdc031b5421035fffa069040c043cd1f3b161601bfe740c79c43d6ebcdcc5126d1c3bd8ac44e0210258bf142b43f402146e2d072c9ef313d863f8f45a95f7d5ace61df57fd8befc5d0b454e444f5253454d454e540353514c210342d943b8dba93a4ce29b858479c67f1e4f1110eecbe1f83dc01b455eb8b123b30106506565724944014100",
    "TxnHashHex": "7a8fec83970a0a564467c05ecf335b86d596ba090012584e34c691641ce70d3f"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

## Delete user association

<mark style="color:green;">`POST`</mark> `/api/v0/user-associations/delete`

Creates a delete user association transaction. The transaction needs to be signed and submitted through `/api/v0/submit-transaction` before changes come into effect.

Implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/associations.go#L265)

#### Request Body

| Name                                                             | Type               | Description                                                                                                                                                                                                                   |
| ---------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | The public key of the user creating the transaction                                                                                                                                                                           |
| AssociationID<mark style="color:red;">\*</mark>                  | String             | The identifier of the association to delete                                                                                                                                                                                   |
| ExtraData                                                        | map\[String]String | Any additional arbitrary key-value data to include with the transaction                                                                                                                                                       |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>           | uint64             | The minimum fee rate (in nanos) per kb                                                                                                                                                                                        |
| TransactionFees                                                  | \[]TransactionFee  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed a delete user association transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "SpendAmountNanos": 0,
    "TotalInputNanos": 999999032,
    "ChangeAmountNanos": 999998590,
    "FeeNanos": 442,
    "Transaction": {
        "TxInputs": [
            {
                "TxID": [
                    22,
                    224,
                    4,
                    226,
                    226,
                    96,
                    82,
                    152,
                    255,
                    93,
                    21,
                    79,
                    44,
                    114,
                    203,
                    120,
                    59,
                    196,
                    155,
                    171,
                    147,
                    53,
                    123,
                    32,
                    255,
                    129,
                    135,
                    193,
                    129,
                    195,
                    178,
                    57
                ],
                "Index": 0
            }
        ],
        "TxOutputs": [
            {
                "PublicKey": "A0LZQ7jbqTpM4puFhHnGfx5PERDuy+H4PcAbRV64sSOz",
                "AmountNanos": 999998590
            }
        ],
        "TxnMeta": {
            "AssociationID": [
                22,
                224,
                4,
                226,
                226,
                96,
                82,
                152,
                255,
                93,
                21,
                79,
                44,
                114,
                203,
                120,
                59,
                196,
                155,
                171,
                147,
                53,
                123,
                32,
                255,
                129,
                135,
                193,
                129,
                195,
                178,
                57
            ]
        },
        "PublicKey": "A0LZQ7jbqTpM4puFhHnGfx5PERDuy+H4PcAbRV64sSOz",
        "ExtraData": {},
        "Signature": {
            "Sign": null,
            "RecoveryId": 0,
            "IsRecoverable": false
        },
        "TxnTypeJSON": 28
    },
    "TransactionHex": "0116e004e2e2605298ff5d154f2c72cb783bc49bab93357b20ff8187c181c3b23900010342d943b8dba93a4ce29b858479c67f1e4f1110eecbe1f83dc01b455eb8b123b3fe88ebdc031c212016e004e2e2605298ff5d154f2c72cb783bc49bab93357b20ff8187c181c3b239210342d943b8dba93a4ce29b858479c67f1e4f1110eecbe1f83dc01b455eb8b123b30000",
    "TxnHashHex": "ad731a94d56ead5850d595b45c86d18981e561a40036683ce9f40b9bc9f8ef93"
}

```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

### Post Associations

## Create post association

<mark style="color:green;">`POST`</mark> `/api/v0/post-associations/create`

Creates a create post association transaction. The transaction needs to be signed and submitted through `/api/v0/submit-transaction` before changes come into effect.

Implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/associations.go#L619)

#### Request Body

| Name                                                             | Type               | Description                                                                                                                                                                                                                   |
| ---------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | The public key of the user creating the transaction                                                                                                                                                                           |
| PostHashHex<mark style="color:red;">\*</mark>                    | String             | The identifier of the post to which the association is referencing                                                                                                                                                            |
| AppPublicKeyBase58Check                                          | String             | The public key of the application on which the association is being created                                                                                                                                                   |
| AssociationType<mark style="color:red;">\*</mark>                | String             | The association type                                                                                                                                                                                                          |
| AssociationValue<mark style="color:red;">\*</mark>               | String             | The association value                                                                                                                                                                                                         |
| ExtraData                                                        | map\[String]String | Any additional arbitrary key-value data to store with the association                                                                                                                                                         |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>           | uint64             | The minimum fee rate (in nanos) per kb                                                                                                                                                                                        |
| TransactionFees                                                  | \[]TransactionFee  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed a create post association transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "SpendAmountNanos": 0,
    "TotalInputNanos": 999998132,
    "ChangeAmountNanos": 999997574,
    "FeeNanos": 558,
    "Transaction": {
        "TxInputs": [
            {
                "TxID": [
                    185,
                    36,
                    7,
                    40,
                    237,
                    109,
                    64,
                    8,
                    28,
                    148,
                    5,
                    239,
                    73,
                    214,
                    19,
                    60,
                    251,
                    248,
                    92,
                    246,
                    20,
                    89,
                    19,
                    199,
                    82,
                    232,
                    165,
                    207,
                    27,
                    140,
                    207,
                    63
                ],
                "Index": 0
            }
        ],
        "TxOutputs": [
            {
                "PublicKey": "A0LZQ7jbqTpM4puFhHnGfx5PERDuy+H4PcAbRV64sSOz",
                "AmountNanos": 999997574
            }
        ],
        "TxnMeta": {
            "PostHash": [
                185,
                36,
                7,
                40,
                237,
                109,
                64,
                8,
                28,
                148,
                5,
                239,
                73,
                214,
                19,
                60,
                251,
                248,
                92,
                246,
                20,
                89,
                19,
                199,
                82,
                232,
                165,
                207,
                27,
                140,
                207,
                63
            ],
            "AppPublicKey": [
                2,
                88,
                191,
                20,
                43,
                67,
                244,
                2,
                20,
                110,
                45,
                7,
                44,
                158,
                243,
                19,
                216,
                99,
                248,
                244,
                90,
                149,
                247,
                213,
                172,
                230,
                29,
                245,
                127,
                216,
                190,
                252,
                93
            ],
            "AssociationType": "UkVBQ1RJT04=",
            "AssociationValue": "SEVBUlQ="
        },
        "PublicKey": "A0LZQ7jbqTpM4puFhHnGfx5PERDuy+H4PcAbRV64sSOz",
        "ExtraData": {
            "PeerID": "Qg=="
        },
        "Signature": {
            "Sign": null,
            "RecoveryId": 0,
            "IsRecoverable": false
        },
        "TxnTypeJSON": 29
    },
    "TransactionHex": "01b9240728ed6d40081c9405ef49d6133cfbf85cf6145913c752e8a5cf1b8ccf3f00010342d943b8dba93a4ce29b858479c67f1e4f1110eecbe1f83dc01b455eb8b123b38681ebdc031d5220b9240728ed6d40081c9405ef49d6133cfbf85cf6145913c752e8a5cf1b8ccf3f210258bf142b43f402146e2d072c9ef313d863f8f45a95f7d5ace61df57fd8befc5d085245414354494f4e054845415254210342d943b8dba93a4ce29b858479c67f1e4f1110eecbe1f83dc01b455eb8b123b30106506565724944014200",
    "TxnHashHex": "d886a0fdcde9245f3799679b290f7c808df0f93396cada2996e13320b7688982"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

## Delete post association

<mark style="color:green;">`POST`</mark> `/api/v0/post-associations/delete`

Creates a delete post association transaction. The transaction needs to be signed and submitted through `/api/v0/submit-transaction` before changes come into effect.

Implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/associations.go#L731)

#### Request Body

| Name                                                             | Type               | Description                                                                                                                                                                                                                   |
| ---------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | The public key of the user creating the transaction                                                                                                                                                                           |
| AssociationID                                                    | String             | The identifier of the association being deleted                                                                                                                                                                               |
| ExtraData                                                        | map\[String]String | Any additional arbitrary key-value data to include with the transaction                                                                                                                                                       |
| MinFeeRateNanosPerKB<mark style="color:red;">\*</mark>           | uint64             | The minimum fee rate (in nanos) per kb                                                                                                                                                                                        |
| TransactionFees                                                  | \[]TransactionFee  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |

{% tabs %}
{% tab title="200: OK Successfully constructed a delete post association transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "SpendAmountNanos": 0,
    "TotalInputNanos": 999997574,
    "ChangeAmountNanos": 999997132,
    "FeeNanos": 442,
    "Transaction": {
        "TxInputs": [
            {
                "TxID": [
                    80,
                    45,
                    189,
                    249,
                    80,
                    253,
                    175,
                    41,
                    234,
                    210,
                    82,
                    131,
                    175,
                    1,
                    114,
                    246,
                    63,
                    83,
                    147,
                    58,
                    39,
                    158,
                    19,
                    145,
                    133,
                    89,
                    183,
                    250,
                    43,
                    243,
                    227,
                    0
                ],
                "Index": 0
            }
        ],
        "TxOutputs": [
            {
                "PublicKey": "A0LZQ7jbqTpM4puFhHnGfx5PERDuy+H4PcAbRV64sSOz",
                "AmountNanos": 999997132
            }
        ],
        "TxnMeta": {
            "AssociationID": [
                80,
                45,
                189,
                249,
                80,
                253,
                175,
                41,
                234,
                210,
                82,
                131,
                175,
                1,
                114,
                246,
                63,
                83,
                147,
                58,
                39,
                158,
                19,
                145,
                133,
                89,
                183,
                250,
                43,
                243,
                227,
                0
            ]
        },
        "PublicKey": "A0LZQ7jbqTpM4puFhHnGfx5PERDuy+H4PcAbRV64sSOz",
        "ExtraData": {},
        "Signature": {
            "Sign": null,
            "RecoveryId": 0,
            "IsRecoverable": false
        },
        "TxnTypeJSON": 30
    },
    "TransactionHex": "01502dbdf950fdaf29ead25283af0172f63f53933a279e13918559b7fa2bf3e30000010342d943b8dba93a4ce29b858479c67f1e4f1110eecbe1f83dc01b455eb8b123b3ccfdeadc031e2120502dbdf950fdaf29ead25283af0172f63f53933a279e13918559b7fa2bf3e300210342d943b8dba93a4ce29b858479c67f1e4f1110eecbe1f83dc01b455eb8b123b30000",
    "TxnHashHex": "0009a31ccc2210a40cb3e44aa7df45fdc15f58b09b95d9349648fb578141ac88"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}

{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}


# Access Groups API

## Create Access Group

<mark style="color:green;">`POST`</mark> `/api/v0/create-access-group`

Prepare an access group transaction to create a new access group. Transaction needs to be signed and submitted through `api/v0/submit-transaction`before changes come into effect.&#x20;

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L176).

#### Request Body

| Name                                                                   | Type               | Description                                                                                                                                                                                                                   |
| ---------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of the user creating the access group. This user will be the owner of the access group.                                                                                                                            |
| AccessGroupPublicKeyBase58Check<mark style="color:red;">\*</mark>      | String             | Public key of the access group that is being created.                                                                                                                                                                         |
| AccessGroupKeyName<mark style="color:red;">\*</mark>                   | String             | Name of the access group that is being created.                                                                                                                                                                               |
| MinFeeRateNanosPerKB                                                   | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                        | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| ExtraData                                                              | map\[String]String | arbitrary key value data                                                                                                                                                                                                      |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "TotalInputNanos": 99967828,
  "ChangeAmountNanos": 99967562,
  "FeeNanos": 266,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [
          200,
          13,
          13,
          151,
          191,
          238,
          44,
          73,
          203,
          166,
          3,
          131,
          33,
          228,
          244,
          13,
          50,
          169,
          228,
          12,
          44,
          74,
          52,
          254,
          114,
          112,
          84,
          50,
          182,
          57,
          30,
          62
        ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 99967562
      }
    ],
    "TxnMeta": {
      "AccessGroupOwnerPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
      "AccessGroupPublicKey": "AxJsKZRZjnXENR0XCY1fL3kTHwLUu7OLfpJhcxraza2+",
      "AccessGroupKeyName": "ZGVtb2NoYXQ=",
      "AccessGroupOperationType": 2
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {},
    "Signature": {
      "Sign": null,
      "RecoveryId": 0,
      "IsRecoverable": false
    },
    "TxnTypeJSON": 31
  },
  "TransactionHex": "01c80d0d97bfee2c49cba6038321e4f40d32a9e40c2c4a34fe72705432b6391e3e000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45cac4d52f1f4e2102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c452103126c2994598e75c4351d17098d5f2f79131f02d4bbb38b7e9261731adacdadbe0864656d6f63686174022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Update Access Group

<mark style="color:green;">`POST`</mark> `/api/v0/update-access-group`

Prepare an access group transaction to update an existing access group. Transaction needs to be signed and submitted through `api/v0/submit-transaction`before changes come into effect.&#x20;

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L183).

#### Request Body

| Name                                                                   | Type               | Description                                                                                                                                                                                                                   |
| ---------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String             | Public key of the user updating their access group. This must be the access group owner.                                                                                                                                      |
| AccessGroupPublicKeyBase58Check<mark style="color:red;">\*</mark>      | String             | Public key of the access group that is being updated.                                                                                                                                                                         |
| AccessGroupKeyName<mark style="color:red;">\*</mark>                   | String             | Name of the access group that is being updated.                                                                                                                                                                               |
| MinFeeRateNanosPerKB                                                   | uint64             | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                        | TransactionFee\[]  | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| ExtraData                                                              | map\[String]String | arbitrary key value data                                                                                                                                                                                                      |

{% tabs %}
{% tab title="200: OK Coming soon!" %}

```javascript
{
  "TotalInputNanos": 99967828,
  "ChangeAmountNanos": 99967562,
  "FeeNanos": 266,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [
          200,
          13,
          13,
          151,
          191,
          238,
          44,
          73,
          203,
          166,
          3,
          131,
          33,
          228,
          244,
          13,
          50,
          169,
          228,
          12,
          44,
          74,
          52,
          254,
          114,
          112,
          84,
          50,
          182,
          57,
          30,
          62
        ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 99967562
      }
    ],
    "TxnMeta": {
      "AccessGroupOwnerPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
      "AccessGroupPublicKey": "AxJsKZRZjnXENR0XCY1fL3kTHwLUu7OLfpJhcxraza2+",
      "AccessGroupKeyName": "ZGVtb2NoYXQ=",
      "AccessGroupOperationType": 3
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {},
    "Signature": {
      "Sign": null,
      "RecoveryId": 0,
      "IsRecoverable": false
    },
    "TxnTypeJSON": 31
  },
  "TransactionHex": "01c80d0d97bfee2c49cba6038321e4f40d32a9e40c2c4a34fe72705432b6391e3e000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45cac4d52f1f4e2102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c452103126c2994598e75c4351d17098d5f2f79131f02d4bbb38b7e9261731adacdadbe0864656d6f63686174022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Add Access Group Members

<mark style="color:green;">`POST`</mark> `/api/v0/add-access-group-members`

Prepare an access group member transaction to add new members to an access group. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L435).

#### Request Body

| Name                                                                   | Type                 | Description                                                                                                                                                                                                                   |
| ---------------------------------------------------------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String               | Public key of the access group owner. Must be the public key signing this transaction.                                                                                                                                        |
| AccessGroupKeyName<mark style="color:red;">\*</mark>                   | String               | Name of the access group to which the members will be added.                                                                                                                                                                  |
| AccessGroupMemberList<mark style="color:red;">\*</mark>                | AccessGroupMember\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#accessgroupmember">/pages/ZMql1yrBqvnDbHsldIax#accessgroupmember</a></p><p>objects representing the users to be added to the access group.</p>            |
| MinFeeRateNanosPerKB                                                   | uint64               | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                        | TransactionFee\[]    | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| ExtraData                                                              | map\[String]String   | arbitrary key value data                                                                                                                                                                                                      |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "TotalInputNanos": 99967562,
  "ChangeAmountNanos": 99966522,
  "FeeNanos": 1040,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [
          128,
          156,
          232,
          236,
          161,
          203,
          117,
          179,
          124,
          43,
          53,
          142,
          175,
          117,
          106,
          235,
          241,
          60,
          176,
          22,
          120,
          33,
          81,
          146,
          181,
          10,
          226,
          106,
          73,
          216,
          212,
          79
        ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 99966522
      }
    ],
    "TxnMeta": {
      "AccessGroupOwnerPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
      "AccessGroupKeyName": "ZGVtb2NoYXQ=",
      "AccessGroupMembersList": [
        {
          "AccessGroupMemberPublicKey": "ApOA89iQNICFoi4H2Nqtnx83BnZ7/dWTN2QcTTIxBGUJ",
          "AccessGroupMemberKeyName": "ZGVmYXVsdC1rZXk=",
          "EncryptedKey": "MDRjZDUyN2RmZGZmMzVmODY0NDkwOTY4MTY1ZWY3ZTM0YTNjYjAwOWFiY2JkZTg2MDE2OTgzNGNhYzg4Yzk4Y2VjMTkyZjY2MWMyNjdkYzY2YmE2ZGVkNDZiOWVmMDczNTllMTc0ZDRmZWE4NzA1MmU4M2YxNzhjYjU0OTE0NWY4NTlhOTMzOGZhOGY0NjU3ZTc0ZmYyMjYxNDJmNDdmYmM0YzRhYWQ2MWNhOThmOGUyZjkwZWY0NTliYWFiYjg2ZWIyYjFhMTM3OGNhMmE2ODA0MWU5OTYwM2NhYzMzMDlhNzQ3ZDMwYzQzYmZiN2E1ODRhNzY4MjY1MGJlOGFhNDliNTU0NzBmNDJmOTQwN2FmMmVlMWNmY2ZkMDY5NzQ1MDQ2OTVkZmQzODNjYmU3ZDhlZmZkYTNmZTgxNWI3Njc1NzQzZjdkZTMyYmIzYTc1MzE4NzRmNjkwNGFlYmIxZjgw",
          "ExtraData": {}
        },
        {
          "AccessGroupMemberPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
          "AccessGroupMemberKeyName": "ZGVmYXVsdC1rZXk=",
          "EncryptedKey": "MDRhYjUzNmFiNWMwOWEyOWExYWE1MzkzNmQ2ZmUzNGY2M2Y1YTgwNTVmODE3YjYzMThhOGM5NzNkOTM2NTM1ZjMxM2FiNzE5N2Q3OWUwNTE3Yjk0OWE1NTc0ZDUwZjk1Mzk1MDk1NTYwNTM4ZTgwMDdjZDM5YTgzZjE0MTYyODU1NGY4Mjk5OTdiNWMzYTYyNjNhN2Q3M2RhZjE3MWZjMmQwNThiZDZkZjUxMmNiN2NhN2ZmMGNlY2E5MzM1N2IyNjhlNTFiY2MxZWRhNTFjNzUwYTY2NTA1YmYzY2Q3NWFhMjgxZGU2MDM3ZTExNjY2ZGI5YzJlNzAwMTA3YTE3NmFmMzVmYTM2OGE3ZGQ2ODNiMGQyYjJlZGM0OWRkMmJlMmRkYjk0YTkzMDdkYWNhZGMxZWM3NTJkN2I2OTM2M2Y5MThiMzAwMmU2MTEzMGY5ODRiY2I5ODM4Y2IxZTM3ODg3",
          "ExtraData": {}
        }
      ],
      "AccessGroupMemberOperationType": 2
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {},
    "Signature": {
      "Sign": null,
      "RecoveryId": 0,
      "IsRecoverable": false
    },
    "TxnTypeJSON": 32
  },
  "TransactionHex": "01809ce8eca1cb75b37c2b358eaf756aebf13cb01678215192b50ae26a49d8d44f000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45babcd52f20d3062102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450864656d6f636861740221029380f3d890348085a22e07d8daad9f1f3706767bfdd59337641c4d32310465090b64656661756c742d6b6579e202303463643532376466646666333566383634343930393638313635656637653334613363623030396162636264653836303136393833346361633838633938636563313932663636316332363764633636626136646564343662396566303733353965313734643466656138373035326538336631373863623534393134356638353961393333386661386634363537653734666632323631343266343766626334633461616436316361393866386532663930656634353962616162623836656232623161313337386361326136383034316539393630336361633333303961373437643330633433626662376135383461373638323635306265386161343962353534373066343266393430376166326565316366636664303639373435303436393564666433383363626537643865666664613366653831356237363735373433663764653332626233613735333138373466363930346165626231663830002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450b64656661756c742d6b6579e20230346162353336616235633039613239613161613533393336643666653334663633663561383035356638313762363331386138633937336439333635333566333133616237313937643739653035313762393439613535373464353066393533393530393535363035333865383030376364333961383366313431363238353534663832393939376235633361363236336137643733646166313731666332643035386264366466353132636237636137666630636563613933333537623236386535316263633165646135316337353061363635303562663363643735616132383164653630333765313136363664623963326537303031303761313736616633356661333638613764643638336230643262326564633439646432626532646462393461393330376461636164633165633735326437623639333633663931386233303032653631313330663938346263623938333863623165333738383700022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Remove Access Group Members

<mark style="color:green;">`POST`</mark> `/api/v0/remove-access-group-members`

Prepare an access group member transaction to remove members from an access group. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.&#x20;

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L442).

#### Request Body

| Name                                                                   | Type                 | Description                                                                                                                                                                                                                                                                                                                   |
| ---------------------------------------------------------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String               | Public key of the access group owner. Must be the public key signing this transaction.                                                                                                                                                                                                                                        |
| AccessGroupKeyName<mark style="color:red;">\*</mark>                   | String               | Name of the access group from which the members will be removed.                                                                                                                                                                                                                                                              |
| AccessGroupMemberList<mark style="color:red;">\*</mark>                | AccessGroupMember\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#accessgroupmember">/pages/ZMql1yrBqvnDbHsldIax#accessgroupmember</a></p><p>objects representing the users to be removed from the access group. Please note that EncryptedKey and ExtraData must be excluded from these objects when removing members.</p> |
| MinFeeRateNanosPerKB                                                   | uint64               | Rate per KB                                                                                                                                                                                                                                                                                                                   |
| TransactionFees                                                        | TransactionFee\[]    | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p>                                                                                                 |
| ExtraData                                                              | map\[String]String   | arbitrary key value data                                                                                                                                                                                                                                                                                                      |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "TotalInputNanos": 99967562,
  "ChangeAmountNanos": 99966522,
  "FeeNanos": 1040,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [
          128,
          156,
          232,
          236,
          161,
          203,
          117,
          179,
          124,
          43,
          53,
          142,
          175,
          117,
          106,
          235,
          241,
          60,
          176,
          22,
          120,
          33,
          81,
          146,
          181,
          10,
          226,
          106,
          73,
          216,
          212,
          79
        ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 99966522
      }
    ],
    "TxnMeta": {
      "AccessGroupOwnerPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
      "AccessGroupKeyName": "ZGVtb2NoYXQ=",
      "AccessGroupMembersList": [
        {
          "AccessGroupMemberPublicKey": "ApOA89iQNICFoi4H2Nqtnx83BnZ7/dWTN2QcTTIxBGUJ",
          "AccessGroupMemberKeyName": "ZGVmYXVsdC1rZXk=",
          "EncryptedKey": "",
          "ExtraData": {}
        },
        {
          "AccessGroupMemberPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
          "AccessGroupMemberKeyName": "ZGVmYXVsdC1rZXk=",
          "EncryptedKey": "",
          "ExtraData": {}
        }
      ],
      "AccessGroupMemberOperationType": 3
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {},
    "Signature": {
      "Sign": null,
      "RecoveryId": 0,
      "IsRecoverable": false
    },
    "TxnTypeJSON": 32
  },
  "TransactionHex": "01809ce8eca1cb75b37c2b358eaf756aebf13cb01678215192b50ae26a49d8d44f000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45babcd52f20d3062102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450864656d6f636861740221029380f3d890348085a22e07d8daad9f1f3706767bfdd59337641c4d32310465090b64656661756c742d6b6579e202303463643532376466646666333566383634343930393638313635656637653334613363623030396162636264653836303136393833346361633838633938636563313932663636316332363764633636626136646564343662396566303733353965313734643466656138373035326538336631373863623534393134356638353961393333386661386634363537653734666632323631343266343766626334633461616436316361393866386532663930656634353962616162623836656232623161313337386361326136383034316539393630336361633333303961373437643330633433626662376135383461373638323635306265386161343962353534373066343266393430376166326565316366636664303639373435303436393564666433383363626537643865666664613366653831356237363735373433663764653332626233613735333138373466363930346165626231663830002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450b64656661756c742d6b6579e20230346162353336616235633039613239613161613533393336643666653334663633663561383035356638313762363331386138633937336439333635333566333133616237313937643739653035313762393439613535373464353066393533393530393535363035333865383030376364333961383366313431363238353534663832393939376235633361363236336137643733646166313731666332643035386264366466353132636237636137666630636563613933333537623236386535316263633165646135316337353061363635303562663363643735616132383164653630333765313136363664623963326537303031303761313736616633356661333638613764643638336230643262326564633439646432626532646462393461393330376461636164633165633735326437623639333633663931386233303032653631313330663938346263623938333863623165333738383700022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Update Access Group Members

<mark style="color:green;">`POST`</mark> `/api/v0/update-access-group-members`

Prepare an access group member transaction to update a member in an access group. Note that you can only update the EncryptedKey and ExtraData attributes of an AccessGroupMember's entry. If you need to change the AccessGroupMemberKeyName, you'll need to remove and re-add them. Transaction needs to be signed and submitted through `api/v0/submit-transaction` before changes come into effect.&#x20;

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L449).

#### Request Body

| Name                                                                   | Type                 | Description                                                                                                                                                                                                                   |
| ---------------------------------------------------------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String               | Public key of the access group owner. Must be the public key signing this transaction.                                                                                                                                        |
| AccessGroupKeyName<mark style="color:red;">\*</mark>                   | String               | Name of the access group in which the members will be updated.                                                                                                                                                                |
| AccessGroupMemberList<mark style="color:red;">\*</mark>                | AccessGroupMember\[] | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#accessgroupmember">/pages/ZMql1yrBqvnDbHsldIax#accessgroupmember</a></p><p>objects representing the users to be updated in this access group.</p>         |
| MinFeeRateNanosPerKB                                                   | uint64               | Rate per KB                                                                                                                                                                                                                   |
| TransactionFees                                                        | TransactionFee\[]    | <p>Array of</p><p><a data-mention href="/pages/ZMql1yrBqvnDbHsldIax#transactionfee">/pages/ZMql1yrBqvnDbHsldIax#transactionfee</a></p><p>objects that define additional outputs that need to be added to this transaction</p> |
| ExtraData                                                              | map\[String]String   | arbitrary key value data                                                                                                                                                                                                      |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "TotalInputNanos": 99967562,
  "ChangeAmountNanos": 99966522,
  "FeeNanos": 1040,
  "Transaction": {
    "TxInputs": [
      {
        "TxID": [
          128,
          156,
          232,
          236,
          161,
          203,
          117,
          179,
          124,
          43,
          53,
          142,
          175,
          117,
          106,
          235,
          241,
          60,
          176,
          22,
          120,
          33,
          81,
          146,
          181,
          10,
          226,
          106,
          73,
          216,
          212,
          79
        ],
        "Index": 0
      }
    ],
    "TxOutputs": [
      {
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
        "AmountNanos": 99966522
      }
    ],
    "TxnMeta": {
      "AccessGroupOwnerPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
      "AccessGroupKeyName": "ZGVtb2NoYXQ=",
      "AccessGroupMembersList": [
        {
          "AccessGroupMemberPublicKey": "ApOA89iQNICFoi4H2Nqtnx83BnZ7/dWTN2QcTTIxBGUJ",
          "AccessGroupMemberKeyName": "ZGVmYXVsdC1rZXk=",
          "EncryptedKey": "MDRjZDUyN2RmZGZmMzVmODY0NDkwOTY4MTY1ZWY3ZTM0YTNjYjAwOWFiY2JkZTg2MDE2OTgzNGNhYzg4Yzk4Y2VjMTkyZjY2MWMyNjdkYzY2YmE2ZGVkNDZiOWVmMDczNTllMTc0ZDRmZWE4NzA1MmU4M2YxNzhjYjU0OTE0NWY4NTlhOTMzOGZhOGY0NjU3ZTc0ZmYyMjYxNDJmNDdmYmM0YzRhYWQ2MWNhOThmOGUyZjkwZWY0NTliYWFiYjg2ZWIyYjFhMTM3OGNhMmE2ODA0MWU5OTYwM2NhYzMzMDlhNzQ3ZDMwYzQzYmZiN2E1ODRhNzY4MjY1MGJlOGFhNDliNTU0NzBmNDJmOTQwN2FmMmVlMWNmY2ZkMDY5NzQ1MDQ2OTVkZmQzODNjYmU3ZDhlZmZkYTNmZTgxNWI3Njc1NzQzZjdkZTMyYmIzYTc1MzE4NzRmNjkwNGFlYmIxZjgw",
          "ExtraData": {}
        },
        {
          "AccessGroupMemberPublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
          "AccessGroupMemberKeyName": "ZGVmYXVsdC1rZXk=",
          "EncryptedKey": "MDRhYjUzNmFiNWMwOWEyOWExYWE1MzkzNmQ2ZmUzNGY2M2Y1YTgwNTVmODE3YjYzMThhOGM5NzNkOTM2NTM1ZjMxM2FiNzE5N2Q3OWUwNTE3Yjk0OWE1NTc0ZDUwZjk1Mzk1MDk1NTYwNTM4ZTgwMDdjZDM5YTgzZjE0MTYyODU1NGY4Mjk5OTdiNWMzYTYyNjNhN2Q3M2RhZjE3MWZjMmQwNThiZDZkZjUxMmNiN2NhN2ZmMGNlY2E5MzM1N2IyNjhlNTFiY2MxZWRhNTFjNzUwYTY2NTA1YmYzY2Q3NWFhMjgxZGU2MDM3ZTExNjY2ZGI5YzJlNzAwMTA3YTE3NmFmMzVmYTM2OGE3ZGQ2ODNiMGQyYjJlZGM0OWRkMmJlMmRkYjk0YTkzMDdkYWNhZGMxZWM3NTJkN2I2OTM2M2Y5MThiMzAwMmU2MTEzMGY5ODRiY2I5ODM4Y2IxZTM3ODg3",
          "ExtraData": {}
        }
      ],
      "AccessGroupMemberOperationType": 4
    },
    "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF",
    "ExtraData": {},
    "Signature": {
      "Sign": null,
      "RecoveryId": 0,
      "IsRecoverable": false
    },
    "TxnTypeJSON": 32
  },
  "TransactionHex": "01809ce8eca1cb75b37c2b358eaf756aebf13cb01678215192b50ae26a49d8d44f000102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45babcd52f20d3062102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450864656d6f636861740221029380f3d890348085a22e07d8daad9f1f3706767bfdd59337641c4d32310465090b64656661756c742d6b6579e202303463643532376466646666333566383634343930393638313635656637653334613363623030396162636264653836303136393833346361633838633938636563313932663636316332363764633636626136646564343662396566303733353965313734643466656138373035326538336631373863623534393134356638353961393333386661386634363537653734666632323631343266343766626334633461616436316361393866386532663930656634353962616162623836656232623161313337386361326136383034316539393630336361633333303961373437643330633433626662376135383461373638323635306265386161343962353534373066343266393430376166326565316366636664303639373435303436393564666433383363626537643865666664613366653831356237363735373433663764653332626233613735333138373466363930346165626231663830002102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450b64656661756c742d6b6579e20230346162353336616235633039613239613161613533393336643666653334663633663561383035356638313762363331386138633937336439333635333566333133616237313937643739653035313762393439613535373464353066393533393530393535363035333865383030376364333961383366313431363238353534663832393939376235633361363236336137643733646166313731666332643035386264366466353132636237636137666630636563613933333537623236386535316263633165646135316337353061363635303562663363643735616132383164653630333765313136363664623963326537303031303761313736616633356661333638613764643638336230643262326564633439646432626532646462393461393330376461636164633165633735326437623639333633663931386233303032653631313330663938346263623938333863623165333738383700022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c450000"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}


# Data: API

## ProfileEntryResponse

Every public key on the DeSo blockchain can have a profile that describes who they are.

The API returns profiles in the form of an object referred to as a ProfileEntryResponse.

Below is an example of a ProfileEntryResponse with explanations about each attributes.

```json5
{
  "PublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2", // Public key
  "Username": "test", // Username of the public key
  "Description": "this is an example description", // Description displayed on the user's profile
  "IsHidden": false, // Deprecated - ignore.
  "IsReserved": false, // If IsReserved is true, this is a reserved prole that can be claimed by tweeting out a link.
  "IsVerified": false, // If IsVerified is true, this profile is verified on the node on which you are querying and will appear with a blue checkmark
  "Comments": null, // Comments that have been made by this user. This is rarely populated.
  "Posts": null, // Posts that have been made by this user.
  "CoinEntry": {
    "CreatorBasisPoints": 10000, // Founder reward percentage in basis points. e.g. 10%. User will take 10% of all creator coin purchases.
    "DeSoLockedNanos": 110694117, // Total amount of DeSo locked in this profile's creator coin. When ranking by coin price, always use DeSoLockedNanos and not CoinPriceDeSoNanos.
    "NumberOfHolders": 2, // Number of users who hold this creator coin.
    "CoinsInCirculationNanos": 2203171427, // Total number of creator coin nanos in circulation.
    "CoinWatermarkNanos": 2203171427, // CoinWatermarkNanos is the highest amount of nanos that have ever been locked in this profile at a single point in time.
    "DeSoLockedNanos": 110694117 // Deprecated - use DeSoLockedNanos
  },
  "DAOCoinEntry": {
    "NumberOfHolders": 1823837, // Number of public keys holding this DAO coin.
    "CoinsInCirculationNanos": "0x3B9ACA00", // The current total supply of this creator's DAO coins represented as a hex string.
    "MintingDisabled": false, // If true, the supply of this DAO coin is fixed and new coins cannot be minted.
    TransferRestrictionStatus: "unrestricted", // The current transfer restriction status of this creator's DAO coin. Unrestricted means you can transfer to anybody, profile_owner_only means you can only transfer TO or FROM this profile's public key, dao_members_only means you can only transfer to user's who already hold this DAO coin, and permanently_unrestricted means there are no restrictions and this status will never be updated again.
  },
  "CoinPriceDeSoNanos": 150729253, // CoinPriceDeSoNanos is the price of this creator's coin in nanos.
  "CoinPriceDeSoNanos": 150729253, // Deprecated - use CoinPriceDeSoNanos
  "UsersThatHODL": [{ // Array of all hodlers of this creator's coin in the form of BalanceEntryResponses (described below). This is not always included.
    "HODLerPublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // Public key of user who is holding this creator's coin.
    "CreatorPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2", // Public Key of the creator
    "HasPurchased": false, // If true, this user has purchased some amount of creator coins of this creator. If false, they have received these creator coins in a transfer.
    "BalanceNanos": 1000000000, // How many nanos of this creator's coin does the HODLer own.
    "NetBalanceInMempool": 0, // How many nanos of this creator's coin does this HODLer own that are still waiting to be mined into a block.
    "ProfileEntryResponse": <ProfileEntryResponse>, // ProfileEntryResponse of the user that is HODLing 
  }],  
  "IsFeaturedTutorialWellKnownCreator": false,
  "IsFeaturedTutorialUpAndComingCreator": false,
  "DESOBalanceNanos": 10000000, // User's balance of DESO in nanos. 
}
```

Objects of this type will be denoted as `<ProfileEntryResponse>` in this documentation.

For reference, `ProfileEntryResponse` is defined in the backend repo [here](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/user.go#L577).

## PostEntryResponse

Posts are the main way creators communicate with the public on DeSo.\
\
Below is an example of a `PostEntryResponse` - the object that represents a post and all it's attributes:

```json5
{
  "PostHashHex": "67f80ea6908b93cca921a2a49ef268ad373756b5ba45aff4e06bf7a31f7f20c0", // Hex of the Post Hash. Used as the unique identifier of this post.
  "PosterPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2", // Public key of the user who made this post.
  "ParentStakeID": "", // Hex of the Parent Post Hash. If populated, this post is a comment on the parent.
  "Body": "testesteart", // Text body of the post.
  "ImageURLs": ["https://images.deso.org/86c5d55150042af2f56b5ed718f5194a42cb072a9f26f5aee9e3afdc7e609c48.gif"], // URLs to images to include in the post
  "VideoURLs": [], // URLs to videos to include in the post
  "RepostedPostEntryResponse": <PostEntryResponse>, // RepostedPostEntryResponse is another post that this post is reposting (similar to retweeting). 
  "CreatorBasisPoints": 1000, // Deprecated
  "StakeMultipleBasisPoints": 12500, // Deprecated
  "TimestampNanos": 1637776136858394400, // Timestamp of the post
  "IsHidden": false, // If true, post is filtered out everywhere.
  "ConfirmationBlockHeight": 180, // Block height at which this post was confirmed.
  "InMempool": false, // If true, this post is still in the mempool and has not been confirmed in a block yet.
  "ProfileEntryResponse": <ProfileEntryResponse>, // This is the profile of the user who created this post.
  "Comments": [<PostEntryResponse>, <PostEntryResponse>], // Array of comments. These PostEntryResponses reference this post as their parent.
  "LikeCount": 123, // Number of likes on this post.
  "DiamondCount": 1092, // Number of diamonds on this post.
  "PostEntryReaderState": {
    "LikedByReader": false, // True if the reader has liked this post, otherwise false.
    "DiamondLevelBestowed": 2, // Number of diamonds the reader has given this post. 
    "RepostedByReader": false, // True if the reader has reposted this post, otherwise false.
    "RepostPostHashHex": "" // Hex of the Post Hash in which the user has reposted this post.
  },
  "InGlobalFeed": false, // If true, this post is included in the global feed.
  "InHotFeed": false, // If true, this post is in the hot feed.
  "IsPinned": false, // If true, this post is pinned to the top of the feeds.
  "PostExtraData": { // PostExtraData can contain any keys and string values to add metadata to a post.
    "Node": "1",
    "EmbedVideoURL": "https://www.youtube.com/watch?v=X-pqNzHyZbM"
  },
  "CommentCount": 2, // Number of comments on this post.
  "RepostCount": 78, // Number of times this post has been reposted.
  "QuoteRepostCount": 10, // Number of times this post has been quote reposted.
  "ParentPosts": [<PostEntryResponse>, <PostEntryResponse>], // Array of PostEntryResponses that represent the parents of this post.
  "IsNFT": true, // If true, this post has been minted as an NFT. False otherwise.
  "NumNFTCopies": 100, // Number of serial numbers that were minted. 
  "NumNFTCopiesForSale": 0, // Number of serial numbers that are currently for sale.
  "NumNFTCopiesBurned": 0, // Number of serial numbers that have been burned.
  "HasUnlockable": false, // If true, when this post is sold as an NFT, the owner will be required to provide some unlockable content.
  "NFTRoyaltyToCreatorBasisPoints": 500, // Percentage in basis points of the royalty that goes to this post's creator when this NFT is sold.
  "NFTRoyaltyToCoinBasisPoints": 1000, // Percentage in basis points of the royalty that is added to the DeSo locked in this post's creator's coin when this NFT is sold.
  "AdditionalDESORoyaltiesMap": { // Map with public key representing users who receive a royalty paid in DESO upon each sale and values are the royalty percentage defined in basis points
    "tBCKYYbGp3iLwhienWLzbLJM1Yi4WKmWRwNNCchhDLtniDqiHPMGK1": 100, // This user would receive 1% of all future sales in DESO 
  },
  "AdditionalCoinRoyaltiesMap": { // Map with public key representing users who receive a royalty in the form of additional DESO locked in their creator coin and values are the royalty percentage defined in basis points.
    "tBCKYYbGp3iLwhienWLzbLJM1Yi4WKmWRwNNCchhDLtniDqiHPMGK1": 200 // This user's creator coin would have 2% of all future sales added as DESO locked in their creator coin  
  },
  "DiamondsFromSender": 0, // Number of diamonds this post received from a sender. Only populated in get-diamonded-posts
  "HotnessScore": 0, // Hotness score is a measure of how engaging a post is. Posts with the highest hotness scores are featured in the Hot Feed.
  "PostMultiplier": 0, // Multiplier applied to this post in the hot feed algorithm.
}
```

Objects of this type will be denoted as `<PostEntryResponse>` in this documentation.

For reference, `PostEntryResponse` is defined in the backend repo [here](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/post.go#L56).

## BalanceEntryResponse

`BalanceEntryResponses` are another common object you will encounter. \
\
`BalanceEntryResponses` describe the amount of a specific creator coin or DAO coin that a user holds.

```json5
{
  "HODLerPublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // Public key of user who is holding this creator's coin or the DAO coin.
  "CreatorPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2", // Public Key of the creator
  "HasPurchased": false, // If true, this user has purchased some amount of creator coins of this creator. If false, they have received these creator coins in a transfer. This field is always false for DAO coins.
  "BalanceNanos": 1000000000, // How many nanos of this creator's coin does the HODLer own. This field is used for creator coins as DAO coins can exceed the max uint64 value.
  "BalanceNanosUint256": "0x3B9ACA00", // Balance Nanos as a hex string. This is used for DAO coins.
  "NetBalanceInMempool": 0, // How many nanos of this creator's coin or DAO coin does this HODLer own that are still waiting to be mined into a block.
  "ProfileEntryResponse": <ProfileEntryResponse>, // ProfileEntryResponse of the HODLer or creator depending upon the context in which the BalanceEntryResponse was retrieved
}
```

Objects of this type will be denoted as `<BalanceEntryResponse>` in this documentation.

For reference, `BalanceEntryResponse` is defined in the backend repo [here](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/shared.go#L209).

## NFTEntryResponse

`NFTEntryResponses` summarize the current state of a single serial number (copy) of an NFT.

```json5
{
  "OwnerPublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public key of the user who owns this serial number
  "SerialNumber": 2, // serial number described by this NFTEntryResponse
  "IsForSale": true, // If true, this serial number is for sale. If false, this serial number is not currently for sale.
  "IsPending": false, // If true, this serial number was transferred to the owner and is pending an acceptance of the NFT transfer. If false, this serial number is not pending an acceptance.
  "MinBidAmountNanos": 0, // Minimum bid amount in nanos allowed on this serial number.
  "IsBuyNow": true, // If true, this serial number can be purchased at the price of BuyNowPriceNanos without requiring an accept nft bid transaction from the owner.
  "BuyNowPriceNanos": 100000000000, // This is the price at which this serial number can be "bought now". A user can "Buy Now" by submitting a bid that matches the buy now price nanos.
  "LastAcceptedBidAmountNanos": 10000000, // Bid amount in nanos representing the last price at which this serial number was sold.
  "HighestBidAmountNanos": 1150000000, // Highest bid amount currently on this serial number.
  "LowestBidAmountNanos": 97680, // Lowest bid amount currently on this serial number.
  "LastOwnerPublicKeyBase58Check": "BC1YLhkVFp84xfJZqN6jCBsdo6bPyuBoxakChg8DJmmvy2jMhZgBaWK", // Public key of the user who last owned this serial number. This is needed to decrypt Unlockable text.
  "EncryptedUnlockableText": "someencryptedtext" // Unlockable content Text encrypted with a shared secret
  "ExtraData": { // Extra data is an arbitrary key value object that add metadata to an NFT
    "SomeKey": "SomeValue"
  }
}
```

Objects of this type will be denoted as `<NFTEntryResponse>` in this documentation.

For reference, `NFTEntryResponse` is defined in the backend repo [here](https://github.com/deso-protocol/backend/blob/1dea89896504ecc89739d88e9ca6097181168439/routes/nft.go#L17).

## NFTCollectionResponse

`NFTCollectionResponses` provide a high-level overview of the current state of an NFT and all its serial numbers.

```json5
{
  "ProfileEntryResponse": <ProfileEntryResponse>, // ProfileEntryResponse of the creator of the NFT
  "PostEntryResponse": <PostEntryResponse>, // PostEntryResponse of the post that is an NFT
  "HighestBidAmountNanos": 2000000000, // Highest bid amount currently on any serial number of this Post
  "LowestBidAmountNanos": 0, // Lowest bid amount currently on any serial number of this Post
  "HighestBuyNowPriceNanos": 2000000000, // Highest buy now price amount currently on any serial number of this Post
  "LowestBuyNowPriceNanos": 0, // Lowest buy now price amount currently on any serial number of this Post
  "NumCopiesForSale": 1, // Number of serial numbers currently for sale of this NFT post.
  "NumCopiesBuyNow": 1, // Number of serial numbers currently for sale of this NFT post that have IsBuyNow = true.
  "AvailableSerialNumbers": [15] // Array of integers representing the set of all serial numbers that are for sale of this NFT post.
}
```

Objects of this type will be denoted as `<NFTCollectionResponse>` in this documentation.

For reference, `NFTCollectionResponse` is defined in the backend repo [here](https://github.com/deso-protocol/backend/blob/1dea89896504ecc89739d88e9ca6097181168439/routes/nft.go#L39).

## TransactionSpendingLimitResponse

`TransactionSpendingLimitResponse` defines the permissions a derived key is authorized to perform on behalf of the owner key.

```json5
{
  "GlobalDESOLimit": 10000000, // The cumulative amount of DESO the derived key is allow to spend on 
                               // behalf of the owner public key
  "TransactionCountLimitMap": { // Map of transaction type to the number of times this derived key is 
                                // allowed to perform this operation on behalf of the owner public key
    "BASIC_TRANSFER": 2, // 2 basic transfer transactions are authorized
    "SUBMIT_POST": 4, // 4 submit post transactions are authorized
  },
  "CreatorCoinOperationLimitMap": { // Map with keys representing public keys of creators
                                    // mapped to objects defining the number of times each
                                    // creator coin operation can be performed. An empty string
                                    // key means the specified operations are authorized on ANY
                                    // creator coin.
    "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s": { // Derived key is authorized to perform the 
                                                                 // following operations on 
                                                                 // BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s's creator coin.
      "any": 3, // Derived key can perform ANY creator coin operation 3 times on this creator coin.
                // note: any operations are used after more specific operations are used up.
      "buy": 2, // Derived key can perform a buy creator coin operation 2 times on this creator coin.
      "sell": 1, // Derived key can perform a sell creator coin operation 1 time on this creator coin.
      "transfer": 3, // Derived key can perform a transfer creator coin operation 3 times on this creator coin.
    },
  },
  "DAOCoinOperationLimitMap": { // Map with keys representing public keys of DAO
                                // mapped to objects defining the number of times each
                                // DAO coin operation can be performed. An empty string
                                // key means the specified operations are authorized on ANY
                                // DAO coin.
    "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s": { // Derived key is authorized to perform the 
                                                                 // following operations on 
                                                                 // BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s's DAO coin.
      "any": 2, // Derived key can perform ANY DAO coin operation 2 times on this DAO coin.
                // note: any operations are used after more specific operations.
      "mint": 3, // Derived key can perform a mint operation 3 times onn this DAO coin.
      "burn": 1, // Derived key can perform a burn operation 1 time on this DAO coin.
      "disable_minting": 1, // Derived key can perform a disable minting operation 1 time on this DAO coin.
      "update_transfer_restriction_status": 2, // Derived key can perform an update_transfer_restriction_status operation 2 times on this DAO coin. 
      "transfer": 1, // Derived key can perform a transfer operation 1 time on this DAO coin.
    }
  },
  "NFTOperationLimitMap": { // Map with keys representing NFT post hash hexes
                            // mapped to objects with keys representing serial numbers 
                            // mapped to objects defining the number of times each
                            // NFT operation can be performed. An empty string
                            // key means the specified operations are authorized on ANY
                            // NFT. A serial number 0 means the specified operations 
                            // are authorized on any serial number for an NFT.
    "b1cf68f5eb829f8c6c42abe009f315ee921d46c91cc6bd3b9cab9dc4851addc1": {
      0: { // Operations defined under serial number 0 can be performed on any serial number for this NFT.
           // Note: serial number 0 operations are used after more specific serial number operations are used up.
        "any": 1, // Derived key can perform any operation on any serial number 1 time.
      },
      1: {
        "update": 1, // Derived key can perform an UPDATE_NFT transaction for this serial number.
        "accept_nft_bid": 2, // Derived key can perform 2 ACCEPT_NFT_BID transactions for this serial number.
        "nft_bid": 3, // Derived key can perform 3 NFT_BID transactions for this serial number.
        "transfer": 1, // Derived key can perform 1 NFT_TRANSFER transaction for this serial number.
        "burn": 1, // Derived key can perform 1 NFT_BURN transaction for this serial number.
        "accept_nft_transfer": 2, // Derived key can perform 2 ACCEPT_NFT_TRANSFER transactions for this serial number.
      }
    }
  },
}
```

Objects of this type will be denoted at `<TransactionSpendingLimitResponse>` in this documentation.

For reference, `TransactionSpendingLimitResponse` is defined in the backend repo [here](https://github.com/deso-protocol/backend/blob/1dea89896504ecc89739d88e9ca6097181168439/routes/transaction.go#L2575).


# Admin Endpoints

## Admin Node Endpoints

### Node Control

```
POST /api/v0/admin/node-control
```

### Get Mempool Stats

```
POST /api/v0/admin/get-mempool-stats
```

TODO

## Admin Transaction Endpoints

### Get Global Params

```
POST /api/v0/admin/get-global-params
```

TODO

### Update Global Params

```
POST /api/v0/admin/update-global-params
```

TODO

### Swap Identity

```
POST /api/v0/admin/swap-identity
```

TODO

## Admin User Endpoints

### Update User Global Metadata

```
POST /api/v0/admin/update-user-global-metadata
```

TODO

### Get All User Global Metadata

```
POST /api/v0/admin/get-all-user-global-metadata
```

TODO

### Get User Global Metadata

```
POST /api/v0/admin/get-user-global-metadata
```

TODO

### Grant Verification Badge

```
POST /api/v0/admin/grant-verification-badge
```

TODO

### Remove Verification Badge

```
POST /api/v0/admin/remove-verification-badge
```

TODO

### Get Verified Users

```
POST /api/v0/admin/get-verified-users
```

TODO

### Get Username Verification Audit Logs

```
POST /api/v0/admin/get-username-verification-audit-logs
```

TODO

## Admin Feed Endpoints

### Update Global Feed

```
POST /api/v0/admin/update-global-feed
```

TODO

### Pin Post

```
POST /api/v0/admin/pin-post
```

TODO

### Remove Nil Posts

```
POST /api/v0/admin/remove-nil-posts
```

TODO


# Associations Endpoints

Description of endpoints used in querying for associations

### User Associations

## Get user association by ID

<mark style="color:blue;">`GET`</mark> `/api/v0/user-associations/{{ associationID }}`

Retrieve a single user association by ID.

#### Path Parameters

| Name                                            | Type   | Description                                   |
| ----------------------------------------------- | ------ | --------------------------------------------- |
| associationID<mark style="color:red;">\*</mark> | string | The identifier of the association to retrieve |

{% tabs %}
{% tab title="200: OK Successfully retrieved the association" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "AssociationID": "22b1dabed784a8ada7c630e1539829df21e485608c13e3b461a37ff97185ff69",
    "TransactorPublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
    "TargetUserPublicKeyBase58Check": "tBCKXU8pf7nkn8M38sYJeAwiBP7HbSJWy9Zmn4sHNL6gA6ahkriymq",
    "AppPublicKeyBase58Check": "tBCKVUCQ9WxpVmNthS2PKfY1BCxG4GkWvXqDhQ4q3zLtiwKVUNMGYS",
    "AssociationType": "ENDORSEMENT",
    "AssociationValue": "SQL",
    "ExtraData": {
        "PeerID": "A"
    },
    "BlockHeight": 38,
    "TransactorProfile": {
        "PublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
        "Username": "sender",
        "Description": "",
        "IsHidden": false,
        "IsReserved": false,
        "IsVerified": false,
        "Comments": null,
        "Posts": null,
        "CoinEntry": {
            "CreatorBasisPoints": 0,
            "DeSoLockedNanos": 0,
            "NumberOfHolders": 0,
            "CoinsInCirculationNanos": 0,
            "CoinWatermarkNanos": 0,
            "BitCloutLockedNanos": 0
        },
        "DAOCoinEntry": {
            "NumberOfHolders": 0,
            "CoinsInCirculationNanos": "0x0",
            "MintingDisabled": false,
            "TransferRestrictionStatus": "unrestricted"
        },
        "CoinPriceDeSoNanos": 0,
        "CoinPriceBitCloutNanos": 0,
        "UsersThatHODL": null,
        "IsFeaturedTutorialWellKnownCreator": false,
        "IsFeaturedTutorialUpAndComingCreator": false,
        "ExtraData": null,
        "DESOBalanceNanos": 36999999438,
        "BestExchangeRateDESOPerDAOCoin": 0
    },
    "TargetUserProfile": null,
    "AppProfile": null
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}

{% endtab %}

{% tab title="400: Bad Request Invalid parameter provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

## Count user associations

<mark style="color:green;">`POST`</mark> `/api/v0/user-associations/count`

Count the number of user associations matching the provided query parameters.

#### Request Body

| Name                           | Type   | Description                                                            |
| ------------------------------ | ------ | ---------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check | string | The public key of the user who created the association                 |
| TargetUserPublicKeyBase58Check | string | The public key of the user to whom the association references          |
| AppPublicKeyBase58Check        | string | The public key of the application on which the association was created |
| AssociationType                | string | The association type (exact match)                                     |
| AssociationTypePrefix          | string | The prefix of the association type (wildcard match)                    |
| AssociationValue               | string | The association value (exact match)                                    |
| AssociationValuePrefix         | string | The prefix of the association value (wildcard match)                   |

{% tabs %}
{% tab title="200: OK Successfully queried for the number of matching associations" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "Count": 1
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

## Count user associations by multiple values

<mark style="color:green;">`POST`</mark> `/api/v0/user-associations/counts`

Count the number of user associations matching the provided query. Here, you can provide an array of association values and the count of associations matching any in that list will be returned.

#### Request Body

| Name                                                | Type      | Description                                                            |
| --------------------------------------------------- | --------- | ---------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check                      | string    | The public key of the user who created the association                 |
| TargetUserPublicKeyBase58Check                      | string    | The public key of the user to whom the association references          |
| AssociationType<mark style="color:red;">\*</mark>   | string    | The association type (exact match)                                     |
| AssociationValues<mark style="color:red;">\*</mark> | \[]string | An array of association values                                         |
| AppPublicKeyBase58Check                             | string    | The public key of the application on which the association was created |

{% tabs %}
{% tab title="200: OK Successfully queried for the number of matching associations" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "Counts": {
        "JAVASCRIPT": 0,
        "SQL": 1
    },
    "Total": 1
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

## Query for user associations

<mark style="color:green;">`POST`</mark> `/api/v0/user-associations/query`

Retrieve user associations matching the provided query parameters.

#### Request Body

| Name                           | Type      | Description                                                                                                                          |
| ------------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| TransactorPublicKeyBase58Check | string    | The public key of the user who created the association                                                                               |
| TargetUserPublicKeyBase58Check | string    | The public key of the user to whom the association references                                                                        |
| AssociationType                | string    | The association type (exact match)                                                                                                   |
| AssociationTypePrefix          | string    | The prefix of the association type (wildcard match)                                                                                  |
| AssociationValue               | string    | The association value (exact match)                                                                                                  |
| AssociationValuePrefix         | string    | The prefix of the association value (wildcard match)                                                                                 |
| Limit                          | integer   | The maximum number of associations to retrieve (default is 100)                                                                      |
| LastSeenAssociationID          | string    | The identifier of the last retrieved association; this parameter functions like an offset allowing users to paginate through results |
| SortDescending                 | boolean   | If true, results are returned in reverse order                                                                                       |
| IncludeTransactorProfile       | boolean   | If true, include the transactors' user profiles in the response                                                                      |
| IncludeTargetUserProfile       | boolean   | If true, include the target users' profiles in the response                                                                          |
| IncludeAppProfile              | boolean   | If true, include the applications' user profiles in the response                                                                     |
| AssociationValues              | \[]string | An array of association values; associations matching any of the values in this list will be returned                                |
| AppPublicKeyBase58Check        | string    | The public key of the application on which the association was created                                                               |

{% tabs %}
{% tab title="200: OK Successfully retrieved matching associations" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "Associations": [
        {
            "AssociationID": "88eb5872de1ae8188e2768874b77dedb3d53fe27df5e7af48783ca8f3d3920f7",
            "TransactorPublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
            "TargetUserPublicKeyBase58Check": "tBCKXU8pf7nkn8M38sYJeAwiBP7HbSJWy9Zmn4sHNL6gA6ahkriymq",
            "AppPublicKeyBase58Check": "tBCKVUCQ9WxpVmNthS2PKfY1BCxG4GkWvXqDhQ4q3zLtiwKVUNMGYS",
            "AssociationType": "ENDORSEMENT",
            "AssociationValue": "SQL",
            "ExtraData": {
                "PeerID": "A"
            },
            "BlockHeight": 33,
            "TransactorProfile": null,
            "TargetUserProfile": null,
            "AppProfile": null
        }
    ],
    "PublicKeyToProfileEntryResponse": {
        "tBCKVUCQ9WxpVmNthS2PKfY1BCxG4GkWvXqDhQ4q3zLtiwKVUNMGYS": null,
        "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX": {
            "PublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
            "Username": "sender",
            "Description": "",
            "IsHidden": false,
            "IsReserved": false,
            "IsVerified": false,
            "Comments": null,
            "Posts": null,
            "CoinEntry": {
                "CreatorBasisPoints": 0,
                "DeSoLockedNanos": 0,
                "NumberOfHolders": 0,
                "CoinsInCirculationNanos": 0,
                "CoinWatermarkNanos": 0,
                "BitCloutLockedNanos": 0
            },
            "DAOCoinEntry": {
                "NumberOfHolders": 0,
                "CoinsInCirculationNanos": "0x0",
                "MintingDisabled": false,
                "TransferRestrictionStatus": "unrestricted"
            },
            "CoinPriceDeSoNanos": 0,
            "CoinPriceBitCloutNanos": 0,
            "UsersThatHODL": null,
            "IsFeaturedTutorialWellKnownCreator": false,
            "IsFeaturedTutorialUpAndComingCreator": false,
            "ExtraData": null,
            "DESOBalanceNanos": 31999999438,
            "BestExchangeRateDESOPerDAOCoin": 0
        }
    }
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

### Post Associations

## Get post association by ID

<mark style="color:blue;">`GET`</mark> `/api/v0/post-associations/{{ associationID }}`

Retrieve a single post association by ID.

#### Path Parameters

| Name                                            | Type   | Description                                   |
| ----------------------------------------------- | ------ | --------------------------------------------- |
| associationID<mark style="color:red;">\*</mark> | string | The identifier of the association to retrieve |

{% tabs %}
{% tab title="200: OK Successfully retrieved the association" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "AssociationID": "0ed4915dec590cf2c6da7c836971d927d8e682c1b5caf6d7e705e5497ff36746",
    "TransactorPublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
    "PostHashHex": "460f8b4125342af8b4de69018d4b07f862bcd0435f63e75cc376cada35845ddc",
    "AppPublicKeyBase58Check": "tBCKVUCQ9WxpVmNthS2PKfY1BCxG4GkWvXqDhQ4q3zLtiwKVUNMGYS",
    "AssociationType": "REACTION",
    "AssociationValue": "HEART",
    "ExtraData": {
        "PeerID": "B"
    },
    "BlockHeight": 37,
    "TransactorProfile": {
        "PublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
        "Username": "sender",
        "Description": "",
        "IsHidden": false,
        "IsReserved": false,
        "IsVerified": false,
        "Comments": null,
        "Posts": null,
        "CoinEntry": {
            "CreatorBasisPoints": 0,
            "DeSoLockedNanos": 0,
            "NumberOfHolders": 0,
            "CoinsInCirculationNanos": 0,
            "CoinWatermarkNanos": 0,
            "BitCloutLockedNanos": 0
        },
        "DAOCoinEntry": {
            "NumberOfHolders": 0,
            "CoinsInCirculationNanos": "0x0",
            "MintingDisabled": false,
            "TransferRestrictionStatus": "unrestricted"
        },
        "CoinPriceDeSoNanos": 0,
        "CoinPriceBitCloutNanos": 0,
        "UsersThatHODL": null,
        "IsFeaturedTutorialWellKnownCreator": false,
        "IsFeaturedTutorialUpAndComingCreator": false,
        "ExtraData": null,
        "DESOBalanceNanos": 35999998542,
        "BestExchangeRateDESOPerDAOCoin": 0
    },
    "PostEntry": {
        "PostHashHex": "460f8b4125342af8b4de69018d4b07f862bcd0435f63e75cc376cada35845ddc",
        "PosterPublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
        "ParentStakeID": "",
        "Body": "Hello, world!",
        "ImageURLs": null,
        "VideoURLs": null,
        "RepostedPostEntryResponse": null,
        "CreatorBasisPoints": 1000,
        "StakeMultipleBasisPoints": 12500,
        "TimestampNanos": 1675274688926964176,
        "IsHidden": false,
        "ConfirmationBlockHeight": 37,
        "InMempool": true,
        "ProfileEntryResponse": null,
        "Comments": null,
        "LikeCount": 0,
        "DiamondCount": 0,
        "PostEntryReaderState": null,
        "IsPinned": false,
        "PostExtraData": {},
        "CommentCount": 0,
        "RepostCount": 0,
        "QuoteRepostCount": 0,
        "ParentPosts": null,
        "IsNFT": false,
        "NumNFTCopies": 0,
        "NumNFTCopiesForSale": 0,
        "NumNFTCopiesBurned": 0,
        "HasUnlockable": false,
        "NFTRoyaltyToCreatorBasisPoints": 0,
        "NFTRoyaltyToCoinBasisPoints": 0,
        "AdditionalDESORoyaltiesMap": {},
        "AdditionalCoinRoyaltiesMap": {},
        "DiamondsFromSender": 0,
        "HotnessScore": 0,
        "PostMultiplier": 0,
        "RecloutCount": 0,
        "QuoteRecloutCount": 0,
        "RecloutedPostEntryResponse": null
    },
    "PostAuthorProfile": {
        "PublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
        "Username": "sender",
        "Description": "",
        "IsHidden": false,
        "IsReserved": false,
        "IsVerified": false,
        "Comments": null,
        "Posts": null,
        "CoinEntry": {
            "CreatorBasisPoints": 0,
            "DeSoLockedNanos": 0,
            "NumberOfHolders": 0,
            "CoinsInCirculationNanos": 0,
            "CoinWatermarkNanos": 0,
            "BitCloutLockedNanos": 0
        },
        "DAOCoinEntry": {
            "NumberOfHolders": 0,
            "CoinsInCirculationNanos": "0x0",
            "MintingDisabled": false,
            "TransferRestrictionStatus": "unrestricted"
        },
        "CoinPriceDeSoNanos": 0,
        "CoinPriceBitCloutNanos": 0,
        "UsersThatHODL": null,
        "IsFeaturedTutorialWellKnownCreator": false,
        "IsFeaturedTutorialUpAndComingCreator": false,
        "ExtraData": null,
        "DESOBalanceNanos": 35999998542,
        "BestExchangeRateDESOPerDAOCoin": 0
    },
    "AppProfile": null
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameter provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

## Count post associations

<mark style="color:green;">`POST`</mark> `/api/v0/post-associations/count`

Count the number of post associations matching the provided query parameters.

#### Request Body

| Name                           | Type   | Description                                                            |
| ------------------------------ | ------ | ---------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check | string | The public key of the user who created the association                 |
| PostHashHex                    | string | The identifier of the post to which the association references         |
| AppPublicKeyBase58Check        | string | The public key of the application on which the association was created |
| AssociationType                | string | The association type (exact match)                                     |
| AssociationTypePrefix          | string | The prefix of the association type (wildcard match)                    |
| AssociationValue               | string | The association value (exact match)                                    |
| AssociationValuePrefix         | string | The prefix of the association value (wildcard match)                   |

{% tabs %}
{% tab title="200: OK Successfully queried for the number of matching associations" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "Count": 1
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

## Count post associations by multiple values

<mark style="color:green;">`POST`</mark> `/api/v0/post-associations/counts`

Count the number of post associations matching the provided query. Here, you can provide an array of association values and the count of associations matching any in that list will be returned.

#### Request Body

| Name                                                | Type      | Description                                                             |
| --------------------------------------------------- | --------- | ----------------------------------------------------------------------- |
| TransactorPublicKeyBase58Check                      | string    | The public key of the user who created the association                  |
| PostHashHex                                         | string    | The identifier of the post to which this association references         |
| AppPublicKeyBase58Check                             | string    | The public key of the application on which this association was created |
| AssociationType<mark style="color:red;">\*</mark>   | string    | The association type (exact match)                                      |
| AssociationValues<mark style="color:red;">\*</mark> | \[]string | An array of association values                                          |

{% tabs %}
{% tab title="200: OK Successfully queried for the number of matching associations" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "Counts": {
        "HEART": 1,
        "LAUGH": 0
    },
    "Total": 1
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}

## Query for post associations

<mark style="color:green;">`POST`</mark> `/api/v0/post-associations/query`

Retrieve post associations matching the provided query parameters.

#### Request Body

| Name                           | Type      | Description                                                                                                                          |
| ------------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| TransactorPublicKeyBase58Check | string    | The public key of the user who created the association                                                                               |
| PostHashHex                    | string    | The identifier of the post to which this association references                                                                      |
| AppPublicKeyBase58Check        | string    | The public key of the application on which this association was created                                                              |
| AssociationType                | string    | The association type (exact match)                                                                                                   |
| AssociationTypePrefix          | string    | The prefix of the association type (wildcard match)                                                                                  |
| AssociationValue               | string    | The association value (exact match)                                                                                                  |
| AssociationValuePrefix         | string    | The prefix of the association value (wildcard match)                                                                                 |
| AssociationValues              | \[]string | An array of association values; associations matching any of the values in this list will be returned                                |
| Limit                          | integer   | The maximum number of associations to retrieve (default is 100)                                                                      |
| LastSeenAssociationID          | string    | The identifier of the last retrieved association; this parameter functions like an offset allowing users to paginate through results |
| SortDescending                 | boolean   | If true, results are returned in reverse order                                                                                       |
| IncludeTransactorProfile       | boolean   | If true, include the transactors' use profiles in the response                                                                       |
| IncludePostEntry               | boolean   | If true, include the target posts' entries in the response                                                                           |
| IncludePostAuthorProfile       | boolean   | If true, include the target posts' authors' user profiles in the response                                                            |
| IncludeAppProfile              | boolean   | If true, include the applications' user profiles in the response                                                                     |

{% tabs %}
{% tab title="200: OK Successfully retrieved matching associations" %}
{% tabs %}
{% tab title="Sample Response" %}

```javascript
{
    "Associations": [
        {
            "AssociationID": "77cc81b90caadf52bdbcadef72bcf87bdeefc31308779b401141c13e52670caf",
            "TransactorPublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
            "PostHashHex": "7bf79e2fe04f8eadb66b9877ce04d55b64e2663fb34b392c2f215ca9d6fba938",
            "AppPublicKeyBase58Check": "tBCKVUCQ9WxpVmNthS2PKfY1BCxG4GkWvXqDhQ4q3zLtiwKVUNMGYS",
            "AssociationType": "REACTION",
            "AssociationValue": "HEART",
            "ExtraData": {
                "PeerID": "B"
            },
            "BlockHeight": 38,
            "TransactorProfile": null,
            "PostEntry": null,
            "PostAuthorProfile": null,
            "AppProfile": null
        }
    ],
    "PublicKeyToProfileEntryResponse": {},
    "PostHashHexToPostEntryResponse": {
        "7bf79e2fe04f8eadb66b9877ce04d55b64e2663fb34b392c2f215ca9d6fba938": {
            "PostHashHex": "7bf79e2fe04f8eadb66b9877ce04d55b64e2663fb34b392c2f215ca9d6fba938",
            "PosterPublicKeyBase58Check": "tBCKXFJEDSF7Thcc6BUBcB6kicE5qzmLbAtvFf9LfKSXN4LwFt36oX",
            "ParentStakeID": "",
            "Body": "Hello, world!",
            "ImageURLs": null,
            "VideoURLs": null,
            "RepostedPostEntryResponse": null,
            "CreatorBasisPoints": 1000,
            "StakeMultipleBasisPoints": 12500,
            "TimestampNanos": 1675278243313851247,
            "IsHidden": false,
            "ConfirmationBlockHeight": 38,
            "InMempool": true,
            "ProfileEntryResponse": null,
            "Comments": null,
            "LikeCount": 0,
            "DiamondCount": 0,
            "PostEntryReaderState": null,
            "IsPinned": false,
            "PostExtraData": {},
            "CommentCount": 0,
            "RepostCount": 0,
            "QuoteRepostCount": 0,
            "ParentPosts": null,
            "IsNFT": false,
            "NumNFTCopies": 0,
            "NumNFTCopiesForSale": 0,
            "NumNFTCopiesBurned": 0,
            "HasUnlockable": false,
            "NFTRoyaltyToCreatorBasisPoints": 0,
            "NFTRoyaltyToCoinBasisPoints": 0,
            "AdditionalDESORoyaltiesMap": {},
            "AdditionalCoinRoyaltiesMap": {},
            "DiamondsFromSender": 0,
            "HotnessScore": 0,
            "PostMultiplier": 0,
            "RecloutCount": 0,
            "QuoteRecloutCount": 0,
            "RecloutedPostEntryResponse": null
        }
    }
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon!
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request Invalid parameters provided" %}

```javascript
{
    "error": "string"
}
```

{% endtab %}
{% endtabs %}


# DeSo Tokens Endpoints

Description of endpoints used for creating and on-chain trading of DeSo Tokens.

<mark style="color:red;">Note: "DAO Coins" are now referred to as "</mark><mark style="color:red;">**DeSo Tokens**</mark><mark style="color:red;">" in all public-facing documentation, but the code and API have not yet been updated to reflect this change.</mark>\
\
\
For endpoints to check ownership of DeSo Tokens, see [Social Endpoints](/deso-backend/api/social-endpoints#get-hodlers-for-public-key) and [Social Endpoints](/deso-backend/api/social-endpoints#is-hodling-public-key).

## Gets All Open Orders on Order Book for a DeSo Token (DAO Coin) Market

<mark style="color:green;">`POST`</mark> `/api/v0/get-dao-coin-limit-orders`

There are two types of markets where DeSo Tokens can be traded on the on-chain order book exchange: 1) markets where a DeSo Token is traded for $DESO, and 2) markets where a DeSo Token is traded for another DeSo Token.

This endpoint returns all open orders given two coins that can be traded against each other. At least one of the two coins must be a DeSo Token.

See [DeSo Tokens Transactions API](/deso-backend/construct-transactions/dao-transactions-api#create-dao-coin-limit-order) for how to create new limit orders to trade DeSo Tokens.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/0af8093227b219de31487ac129e799fee61e39ef/routes/dao_coin_exchange.go#L37).

#### Request Body

| Name                                                                             | Type   | Description                                                                                                                                                                                            |
| -------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| DAOCoin2CreatorPublicKeyBase58CheckOrUsername2<mark style="color:red;">\*</mark> | string | <p>Public key or username of the creator of the DAO, whose DeSo Token makes up the second side of the market.</p><p></p><p>An empty string here represents $DESO as the second side of the market.</p> |
| DAOCoin1CreatorPublicKeyBase58CheckOrUsername<mark style="color:red;">\*</mark>  | string | <p>Public key or username of the creator of the Token, whose DeSo Token makes up one side of a market.</p><p></p><p>An empty string here represents $DESO as one side of the market.</p>               |

{% tabs %}
{% tab title="200: OK Successfully retrieved all open orders for a coin pair" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
   "Orders":[
      {
         "TransactorPublicKeyBase58Check":"tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // public key of the creator of this order
         "BuyingDAOCoinCreatorPublicKeyBase58Check":"tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // public key of the creator of a DAO coin
         "SellingDAOCoinCreatorPublicKeyBase58Check":"", // empty string represents $DESO
         "ExchangeRateCoinsToSellPerCoinToBuy":3.1,
         "QuantityToFill":5.2, // Denominated in number of coins (not nanos) and can have fractional values
         "OperationType":"BID",
         "OrderID":"4671f48ec7a0da7d769219efdf1689ed19cb3527ae3c1a9669dd5539c9674426" // unique identifier for this order, also equivalent to the transaction hex hash that created the order
      },
      {
         "TransactorPublicKeyBase58Check":"tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV",
         "BuyingDAOCoinCreatorPublicKeyBase58Check":"tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV",
         "SellingDAOCoinCreatorPublicKeyBase58Check":"",
         "ExchangeRateCoinsToSellPerCoinToBuy":0.333,
         "QuantityToFill":1.2,
         "OperationType":"BID",
         "OrderID":"a6c5ab24cde484d91a32b0f977eac2439614192311c7452d8477e4b9a821fc1c"
      },
      
   ]
}

```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    "error": "..." // Error message
}
```

{% endtab %}

{% tab title="500: Internal Server Error " %}

```javascript
{
    "error": "..." // Error message
}
```

{% endtab %}
{% endtabs %}

## Gets All Open Limit Orders Created by a Transactor

<mark style="color:green;">`POST`</mark> `/api/v0/get-transactor-dao-coin-limit-orders`

This endpoint returns all open orders that were created by a given transactor on the DeSo Tokens on-chain order book exchange.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/0af8093227b219de31487ac129e799fee61e39ef/routes/dao_coin_exchange.go#L136).

#### Request Body

| Name                                                                       | Type   | Description                                                               |
| -------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------- |
| TransactorPublicKeyBase58CheckOrUsername<mark style="color:red;">\*</mark> | string | Public key or username of the user whose open orders we want to retrieve. |

{% tabs %}
{% tab title="200: OK Successfully retrieved all open orders for the transactor" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
   "Orders":[
      {
         "TransactorPublicKeyBase58Check":"tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // public key of the creator of this order
         "BuyingDAOCoinCreatorPublicKeyBase58Check":"tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // public key of the creator of a DAO coin
         "SellingDAOCoinCreatorPublicKeyBase58Check":"", // empty string represents $DESO
         "ExchangeRateCoinsToSellPerCoinToBuy":3.98734,
         "QuantityToFill":5.123457, // Denominated in number of coins (not nanos) and can have fractional values
         "OperationType":"BID",
         "OrderID":"4671f48ec7a0da7d769219efdf1689ed19cb3527ae3c1a9669dd5539c9674426" // unique identifier for this order, also equivalent to the transaction hex hash that created the order
      },
   ]
}

```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    "error": "..." // Error message
}
```

{% endtab %}

{% tab title="500: Internal Server Error " %}

```javascript
{
    "error": "..." // Error message
}
```

{% endtab %}
{% endtabs %}


# Media Endpoints

Description of endpoints used to manage media uploads for posts on the DeSo blockchain

## Upload Image

<mark style="color:green;">`POST`</mark> `/api/v0/upload-image`

Uploads an image to be included in a post and returns the URL where the image is stored. This endpoint also handles the resizing of the image.

Note that the request body should have `multipart/form-data` as the content type.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/media.go#L111).

Example usages in frontend:\
&#x20; \- Make request to [Upload Image](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L825)\
&#x20; \- Use UploadImage to [upload an image when a user is making a post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/feed/feed-create-post/feed-create-post.component.ts#L279)

#### Request Body

| Name                                                       | Type   | Description                                                                         |
| ---------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------- |
| UserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the user uploading the image.                                         |
| JWT<mark style="color:red;">\*</mark>                      | String | JWT of the user uploading the image.                                                |
| file<mark style="color:red;">\*</mark>                     | File   | image file to upload. Must be gif, jpeg, png, or webp file. Must be less than 10 MB |

{% tabs %}
{% tab title="200: OK Successfully uploaded image and response has URL at which image can be found" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "ImageURL": "https://images.deso.org/675fc5d13f397d6ce7801b0a76ca928822a768b606d16df1eb015b2e84ed81e5.gif"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

| Name     | Type   | Description                                  |
| -------- | ------ | -------------------------------------------- |
| ImageURL | String | URL at which the uploaded image can be found |

## Upload Video

<mark style="color:green;">`POST`</mark> `/api/v0/upload-video`

UploadVideo creates a one-time tokenized URL that can be used to upload larger video files using the tus protocol. The client uses the Location header in the response from this function to upload the file. The client uses the Stream-Media-Id header in the response from cloudflare to understand how to access the file for streaming.&#x20;

For more details, see the Cloudflare documentation on direct creator uploads [here](https://developers.cloudflare.com/stream/uploading-videos/direct-creator-uploads#using-tus-recommended-for-videos-over-200mb)

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/media.go#L306).

For an example of uploading a video using this endpoint and the tus protocol, see the [implementation in frontend](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/feed/feed-create-post/feed-create-post.component.ts#L291).\
\
After the upload finishes, you can check if the video is ready to be streamed by hitting the [#get-video-status](#get-video-status "mention")endpoint

#### Headers

| Name                                            | Type   | Description                                                                                                                                                                                   |
| ----------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Upload-Length<mark style="color:red;">\*</mark> | Number | Length of video to be uploaded in bytes                                                                                                                                                       |
| Upload-Metadata                                 | JSON   | Arbitrary metadata values - see [cloudflare documentation for more details](https://developers.cloudflare.com/stream/uploading-videos/upload-video-file#supported-options-in-upload-metadata) |

{% tabs %}
{% tab title="200: OK Successfully created one-time tokenized URL that can be used to upload a video" %}
The Location header specifies the one-time tokenized URL. The Stream-Media-Id header is the ID used to stream the video from cloudflare after uploading the video.
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Video Status

<mark style="color:blue;">`GET`</mark> `/api/v0/get-video-status/{videoId}`

Get Video Status queries cloudflare's API to see if a video is ready to be streamed. This is useful in showing a preview of an uploaded video to an end-user when they are creating a post.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/media.go#L372).

Example usage in frontend:\
&#x20; \- Make request to [Get Video Status](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L2228)\
&#x20; \- Use GetVideoStatus to [poll and see if a video is ready to be streamed after a user finished uploading it.](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/lib/services/stream/cloudflare-stream-service.ts#L31)

#### Path Parameters

| Name                                      | Type   | Description                                                                |
| ----------------------------------------- | ------ | -------------------------------------------------------------------------- |
| videoId<mark style="color:red;">\*</mark> | String | videoId retrieved from the `stream-media-id` header when uploading a video |

{% tabs %}
{% tab title="200: OK Successfully queried Cloudflare for the status of the video" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "ReadyToStream": true // If true, video is ready to stream. If false, video is not ready to strea
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

| Name          | Type    | Description                                                                                            |
| ------------- | ------- | ------------------------------------------------------------------------------------------------------ |
| ReadyToStream | Boolean | If true, the video is ready to be streamed. If false, the video is still being processed by cloudflare |

## Get Full TikTok URL

<mark style="color:green;">`POST`</mark> `/api/v0/get-full-tiktok-url`

Given a short video ID of a TikTok, find the URL that can be used to embed this video. The short URL users get when copying a link to a TikTok from TikTok's mobile app isn't embeddable, so this endpoint allows us to find the desktop version of the URL from which we can construct an embeddable version of the URL.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/media.go#L244).

Example usages in frontend:\
&#x20; \- Make request to [Get Full TikTok URL](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1962)\
&#x20; \- Use GetFullTikTokURL to [get an embeddable URL for the short form TikTok url](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/lib/services/embed-url-parser-service/embed-url-parser-service.ts#L147)

#### Request Body

| Name                                                 | Type   | Description                                                                                                                                                                            |
| ---------------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TikTokShortVideoID<mark style="color:red;">\*</mark> | String | <p>Video ID found at the end of a URL copied from the TikTok mobile app. </p><p></p><p>For example, <code>TTPd2Eobq3</code> is the VideoID in <https://vm.tiktok.com/TTPd2Eobq3/`></p> |

{% tabs %}
{% tab title="200: OK Successfully retrieved the embeddable version of the mobile TikTok URL provided" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "FullTikTokURL": "https://m.tiktok.com/v/7037137657872403718.html?_d=secCgYIASAHKAESPgo8T1WVnwCQv6PNczjlfPqZ%2BVrGtkECbrVIwDlSfs8Eubr5IYCCt7sen3HRJwDN44tt0IeLho5JoaUMWgAnGgA%3D&checksum=be13618b6e8d0eacdf95a8abd952ca14e997a5af0126908fb195dca7ab5082d5&language=en&preview_pb=0&sec_user_id=MS4wLjABAAAACRLophxm1bvJ6oYFi4m52AIzepq8Naslxs3ATZs1YCLXomDfhhDOvxsW9DemYFYU&share_app_id=1233&share_item_id=7037137657872403718&share_link_id=2E462ECA-A6B5-44CF-9A9A-BD3F25E5F6FF&source=h5_m&timestamp=1638557967&tt_from=copy&u_code=djcd82ge94k75m&user_id=6980837453575472134&utm_campaign=client_share&utm_medium=ios&utm_source=copy"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

| Name          | Type   | Description                                                                                          |
| ------------- | ------ | ---------------------------------------------------------------------------------------------------- |
| FullTikTokURL | String | Desktop version of the mobile TikTok URL provided in the request body that can be embedded in a post |


# Miner Endpoints

Description of endpoints used to get data related to mining on the DeSo blockchain

## Get Block Template

<mark style="color:green;">`POST`</mark> `/api/v0/get-block-template`

Get the template for the next block

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/miner.go#L56).

Example usages in frontend:\
&#x20; \- Make request to [Get Block Template](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L584)\
&#x20; \- Use GetBlockTemplate to [show stats on the next block in the admin panel](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/admin/admin.component.ts#L405)

#### Request Body

| Name                                                   | Type   | Description                                       |
| ------------------------------------------------------ | ------ | ------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key to swap in for the block reward        |
| NumHeaders<mark style="color:red;">\*</mark>           | int64  | Number of headers (and extra nonces) requested    |
| HeaderVersion<mark style="color:red;">\*</mark>        | uint32 | Must be 1, version 0 headers have been deprecated |

{% tabs %}
{% tab title="200: OK Successfully retrieved the template for the next block" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "BlockID": "27c0be6aba42ae4641c95d9a920399f689450f94388a7ac26c11188eb3b689b0", // Hex of latest block template hash
  "DifficultyTargetHex": "000000000000673b615ce18c1f9ddc322745eb8fb6f55b1debefc4bbbaf7db8a", // Hex of the current difficulty target
  "ExtraNonces": [1], // extra nonces in the block reward metadata
  "Headers": [[1,2,3]], // bytes of the headers of the block
  "LatestBlockTemplateStats": {
    "TxnCount": 0, // Number of transactions in the block template
    "FailingTxnError": "You good", // Reason why the final transaction failed to add. If no error, "You good" returned.
    "FailingTxnHash": "Nada", // Hash of final transaction tatempted to be put into the block that failed. If no error, "Nada" returned.
    "FailingTxnMinutesSinceAdded": 0, // Time since the failing transaction was added to the mempool 
    "FailingTxnOriginalTimeAdded": "2021-12-07T16:22:47.018211613Z" // The time of the first block in which the failed transaction was added.
  }
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Submit Block

<mark style="color:green;">`POST`</mark> `/api/v0/submit-block`

Submits block to be processed by node's block producer

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/miner.go#L125).

#### Request Body

| Name                                                   | Type    | Description                                                 |
| ------------------------------------------------------ | ------- | ----------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String  | Public key to swap in for the block reward                  |
| Header<mark style="color:red;">\*</mark>               | Byte\[] | Bytes of MsgDeSoHeader to be used in block                  |
| ExtraNonce<mark style="color:red;">\*</mark>           | uint64  | Extra data nonce to be used in the block reward transaction |
| BlockID<mark style="color:red;">\*</mark>              | String  | ID of block to be looked up from the block producer         |

{% tabs %}
{% tab title="200: OK Successfully submitted block to be processed" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "IsMainChain": true, // If true, this is a block for the mainchain. If false, this is a block for testnet.
  "IsOrphan": false, // If true, this is an orphan block. If false, this block is not an orphan.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# Notification Endpoints

Description of endpoints used to get notification data on the DeSo blockchain

Please make sure you've read [Data: API](/deso-backend/api) so you are familiar with the following types referenced in this documentation:

* [Data: API](/deso-backend/api#profileentryresponse)
* [Data: API](/deso-backend/api#postentryresponse)
* [Data: API](/deso-backend/api#balanceentryresponse)
* [Data: API](/deso-backend/api#nftentryresponse)
* [Data: API](/deso-backend/api#nftcollectionresponse)

## Get Notifications

<mark style="color:green;">`POST`</mark> `/api/v0/get-notifications`

Get user notifications.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L1877).

Example usages in frontend:\
&#x20; \- Make request to [Get Notifications](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1605)\
&#x20; \- Use GetNotifications to [get the next page of notifications for a user](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/notifications-page/notifications-list/notifications-list.component.ts#L46)

#### Request Body

| Name                                                   | Type             | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| ------------------------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String           | user public key                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| FetchStartIndex                                        | int64            | Index of notification at which to start paginated lookup. Can set to -1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| NumToFetch<mark style="color:red;">\*</mark>           | int64            | Number of notifications to fetch                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| FilteredOutNotificationCategories                      | map\[string]bool | <p>map of category name to boolean indicating whether or not to include this category of transaction types. if not provided, no filtering occurs.<br><br>Category names and transaction types included in category:<br>  - <code>diamond</code>: <code>BasicTransfer</code> or <code>CreatorCoinTransfer</code> transactions that have appropriate diamond extra data.<br>  - <code>transfer</code>: <code>BasicTransfer</code> or <code>CreatorCoinTransfer</code> transactions that do not have diamond extra data OR <code>CreatorCoin</code> (buy or sell) transactions.<br>  - <code>post</code>: <code>Post</code> transactions<br>  - <code>follow</code>: <code>Follow</code> transactions<br>  - <code>like</code>: <code>Like</code> transactions<br>  - <code>nft</code>: <code>NFTBid,</code> <code>AcceptNFTBid</code>,  <code>NFTTransfer</code> , <code>CreateNFT</code>, or <code>UpdateNFT</code> transactions</p><p>  - <code>dao</code>: <code>DAOCoin</code>, <code>DAOCoinTransfer</code>, or <code>DAOCoinLimitOrder</code> transactions</p> |

{% tabs %}
{% tab title="200: OK Successfully retrieved the next page of notifications" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "LastSeenIndex": 100, // Index of the last notification the user has seen
  "Notifications": [
    {
      "Index": 99, // Index of this notification in the list of all notifications for the given public key
      "Metadata": { // Metadata that describe the transaction
        "AffectedPublicKeys": [{
          "Metadata": "BasicTransferOutput", // For a list of all AffectedPublicKey Metadata values - see over here...,
          "PublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", 
        }],
        "BlockHashHex": "0000000000006a8e90b36c0ac36dbe9bc9f97252ab5418abc4d0e2bb2e3d923f", // Hex of the block hash
        "TransactorPublicKeyBase58Check": "BC1YLfhPNqmoAUSDwoQBJrAZRbW4XFA7db89Awpr7GJdN9pWcBZVweQ", // Public key of the user who created the transaction that generated this notification
        "TxnIndexInBlock": 850, // Index of the transaction in the block for which this notification was generated
        "TxnOutputs": [
          {
            "PublicKey": "AgNw/nCxUVblm/dDy0qGleAUqZfdIdiuOBtALN4TdhII", // Public key bytes - this is not particularly useful.
            "AmountNanos": 792289, // Amount of Deso in nanos in this transaction output.
          }
        ],
        "BasicTransferTxindexMetadata": { // Describes basic transfer in transaction. Appears for all notifications
          "TotalInputNanos": 100, // Total DeSo nanos in the inputs of this transaction
          "TotalOutputNanos": 90, // Total Deso nanos in the outputs of this transaction
          "FeeNanos": 20, // Total fees of this transaction
          "UtxoOpsDump": "",
          "UtxoOps": <UtxoOperation>, // UTXO operation to be documented
          "DiamondLevel": 1, // Number of diamonds given by this basic transfer
          "PostHashHex": "43b943880ff21f67b92941553233b9d0e6bcf7c56e9a533416873d4d0798d290" // Hex of Post hash for which diamonds were given by this transaction
        },
        "BitcoinExchangeTxindexMetadata": { // Describes bitcoin exchange transaction. Only appears for Bitcoin Exchange transactions
          "BitcoinSpendAddress": "1B9MXT8sME3Z7kNLTfRDqeKdcUKiF1qhPr", // Address from which BTC was burned
          "SatoshisBurned": 100, // Total Satoshis burned by the transactor
          "NanosCreated": 10, // Total nanos created by this transaction. Note: the DeSo supply is now fixed.
          "TotalNanosPurchasedBefore": 10000, // Total nanos minted by the DeSo protocol before this transaction. Note: the DeSo supply is now fixed.
          "TotalNanosPurchasedAfter": 1010, // Total nanos minted by the DeSo protocol after this transaction. Note: the DeSo supply is now fixed. 
          "BitcoinTxnHash": "833ec95b45707667d29d9cecfdc8dd86006ab0fc8214f395e206437902a9cc9f" // Hash of BTC transaction that exchanged BTC for DeSo
        },
        "CreatorCoinTxindexMetadata": { // Describes creator coin buy/sell transaction. Only appears for Creator coin transactions.
          "OperationType": "buy", // Valid values are "buy" and "sell". "buy" means this transaction was a creator coin purchase. "sell" means this transaction was a creator coin sale.
          "DeSoToSellNanos": 1000, // The amount of DeSo in nanos spent to purchase creator coins. This is only populated if OperationType is "buy"
          "CreatorCoinToSellNanos": 0, // The amount of creator coin in nanos sold. This is only populated if the OperationType is "sell"
          "DeSoToAddNanos": 0, // Note: this field is not currently used.
          "DESOLockedNanosDiff": 1000, // diff in the amount of DeSo locked in a creator coin as a result of this transaction
        },
        "CreatorCoinTransferTxindexMetadata": { // Describes creator coin transfer transaction. Only appears for Creator coin transfer transactions
          "CreatorUsername": "LazyNina", // User of the creator whose coins are transferred in this transaction
          "CreatorCoinToTransferNanos": 1000, // Amount of creator coins of CreatorUsername that were transferred in this transaction
          "DiamondLevel": 2, // Number of diamonds given by this creator coin transfer. Note: diamonds are no longer given in Creator Coins
          "PostHashHex": "43b943880ff21f67b92941553233b9d0e6bcf7c56e9a533416873d4d0798d290", // Hex of Post hash for which diamonds were given by this transaction. Note: diamonds are no longer given in creator coins.
        },
        "UpdateProfileTxindexMetadata": { // Describe update profile transaction. Only appears for Update profile transactions.
          "ProfilePublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public key of the user whose profile was updated
          "NewUsername": "LazyNina", // New username in the user's profile
          "NewDescription": "reading the paper, going to movies", //  New description in the user's profile
          "NewProfilePic": "", // Base64 encoded profile picture in the user's profile
          "NewCreatorBasisPoints": 1000, // Founder reward for the user in basis points.
          "NewStakeMultipleBasisPoints": 0, // Deprecated
          "IsHidden": false, // Whether this profile is hidden or not
        },
        "SubmitPostTxindexMetadata": { // Describes submit post transaction. Only appears for submit post transactions.
          "PostHashBeingModifiedHex": "43b943880ff21f67b92941553233b9d0e6bcf7c56e9a533416873d4d0798d290", // Hex of Post hash that is created by or modified by this transaction
          "ParentPostHashHex": "", // Hex of Post hash that is the parent of PostHashBeingModifiedHex if there is one.
        },
        "LikeTxindexMetadata": { // Describes like transaction. Only appears for like transactions.
          "IsUnlike": false, // If true, this transaction remove an existing like on a post. If false, this transaction add a like on a post.
          "PostHashHex": "43b943880ff21f67b92941553233b9d0e6bcf7c56e9a533416873d4d0798d290" // Hex of Post hash that is liked (or unliked) by this transaction.
        },
        "FollowTxindexMetadata": { // Describes follow transaction. Only appears for follow transactions.
          "IsUnfollow": false, // If true, this transaction removes a creator from a user's following list. If false, this transaction add a creator to a user's following list.
        },
        "PrivateMessageTxindexMetadata": { // Describes private message transaction. Only appears for private message transactions.
          "TimestampNanos": 1000, // Timestamp of private message
        },
        "SwapidentityTxindexMetadata": { // Describes swap identity transaction. Only appears for swap identity transactions.
          "FromPublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public key of the "from" user being swapped
          "ToPublicKeyBase58Check": "BC1YLgU67opDhT9bTPsqvue9QmyJLDHRZrSj77cF3P4yYDndmad9Wmx", // Public key of the "to" user being swapped
          
          "FromDeSoLockedNanos": 1000, // DeSoLocked in from's creator coin after this transaction. Note this field is only needed for Rosetta
          "ToDeSoLockedNanos": 2000, // DeSoLocked in to's creator coin after this transaction. Note this field is only needed for Rosetta
        },
        "NFTBidTxindexMetadata": { // Describes NFT bid transaction. Only appears for NFT bid transactions.
          "NFTPostHashHex": "43b943880ff21f67b92941553233b9d0e6bcf7c56e9a533416873d4d0798d290", // Hex of Post hash that is being bid on in this transaction
          "SerialNumber": 10, // Serial number on which this bid is submitted
          "BidAmountNanos": 1000, // Amount of DeSo (in nanos) bid on the NFT in this transaction.
          "IsBuyNowBid": true, // If true, this bid was a bid on a Buy Now NFT that exceeded the Buy Now Price, resulting in a purchase of the NFT
          "CreatorCoinRoyaltyNanos": 100, // Amount of royalties going to the NFT creator's creator coin in this transaction. 
          "CreatorRoyaltyNanos": 200, // Amount of royalties going to the NFT creator's wallet in the form of DESO in this transaction.
          "CreatorPublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public key of the creator of the NFT
          "AdditionalCoinRoyaltiesMap": { // Map of public key to DESO nanos representing the royalties to the public key's creator coin
            "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2": 50,
          },
          "AdditionalDESORoyaltiesMap": { // Map of public key to DESO nanos representing the royalties paid to public key in the form of DESO
            "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2": 25,
          },
          "OwnerPublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV", // Public key of the owner at the time of the bid
        },
        "AcceptNFTBidTxindexMetadata": { // Describe Accept NFT bid transactions. Only appears for accept NFT bid transactions.
          "NFTPostHashHex": "43b943880ff21f67b92941553233b9d0e6bcf7c56e9a533416873d4d0798d290", // Hex of Post hash that is  sold in this transaction
          "SerialNumber": 10, // Serial number that is sold in this transaction 
          "BidAmountNanos": 1000, // Amount of DeSo (in nanos) of the bid that was accepted in this transaction.
          "CreatorCoinRoyaltyNanos": 100, // Amount of royalties going to the NFT creator's creator coin in this transaction. 
          "CreatorRoyaltyNanos": 200, // Amount of royalties going to the NFT creator's wallet in the form of DESO in this transaction.
          "CreatorPublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public key of the creator of the NFT
          "AdditionalCoinRoyaltiesMap": { // Map of public key to DESO nanos representing the royalties to the public key's creator coin
            "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2": 50,
          },
          "AdditionalDESORoyaltiesMap": { // Map of public key to DESO nanos representing the royalties paid to public key in the form of DESO
            "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2": 25,
          }
        },
        "UpdateNFTTxindexMetadata": { // Describes the Update NFT transaction
          "NFTPostHashHex": "3588e0a85e463966e91b0ec429de9b3edd9f5c9fad3c555c60af358e0688c801", // Hex of Post hash for the NFT that is updated in this transaction
          "IsForSale": true, // If true, this NFT has been put on sale
        },
        "CreateNFTTxindexMetadata": { // Describe the Create NFT transaction
          "NFTPostHashHex": "3588e0a85e463966e91b0ec429de9b3edd9f5c9fad3c555c60af358e0688c801", // Hex of Post hsah for the NFT that is being created in this transaction
          "AdditionalCoinRoyaltiesMap": { // Map of public key to basis points for additional coin royalty
            "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2": 100
          },
          "AdditionalDESORoyaltiesMap": { // Map of public key to basis points for additional DESO royalty
            "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV": 500
         }
        },
        "DAOCoinTxindexMetadata": { // Describes the DAO Coin transaction
          "CreatorUsername": "LazyNina", // Username of DAO creator
          "OperationType": "mint", // String of operation type. Expected values are mint, burn, disable_minting, and update_transfer_restriction_status
          "CoinsToMintNanos": "0x5F5E100", // Hex string representing the number of coins minted in this operation
          "CoinsToBurnNanos": "0x0", // Hex string representing the number of coins burned in this operation
          "TransferRestrictionStatus": "", // String representing the transfer restriction status set in this transaction. Valid values are "Unrestricted", "Profile Owner Only", "DAO Members Only", and "Permanently Unrestricted"
        },
        "DAOCoinTransferTxindexMetadata": {
          "CreatorUsername": "LazyNina", // Username of DAO creator
          "DAOCoinToTransferNanos": "0x5F5E100", // Hex string representing the number of DAO coins transferred in this transaction
        },
      },
      "Txn": null,
      "TxnOutputResponses": [{ // Outputs from the transaction that generated this notification
        "AmountNanos": 1000, // Amount of nanos in this output
        "PublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public key of the recipient of this output
      }]
    }
  ],
  "PostsByHash": { // Map of post hash hex to PostEntryResponse that can be used to add post data to a notification
    "63d6b65c4b270cc538ca0cbd2bb538b8d30de1dda9b397e25c68581e3e4bc209": <PostEntryResponse>,
    ...
  },
  "ProfilesByPublicKey": { // Map of public key to ProfileEntryResponse that can be used to add user profile data to a notification
    "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s": <ProfileEntryResponse>,
  }
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Unread Notification Count

<mark style="color:green;">`POST`</mark> `/api/v0/get-unread-notifications-count`

Gets the number of unread notifications.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L1795).

Example usages in [diamondapp.com](https://diamondapp.com)'s frontend:\
&#x20; \- Make request to [Get Unread Notification Count](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/backend-api.service.ts#L1706)\
&#x20; \- Use GetUnreadNotificationCount to [display an indicator next to notifications representing the number of unread notifications ](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/global-vars.service.ts#L274)

#### Request Body

| Name                                                   | Type   | Description                                                           |
| ------------------------------------------------------ | ------ | --------------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the user for whom we want to get the notification count |

{% tabs %}
{% tab title="200: OK Successfully retrieved the number of unread notifications" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "NotificationsCount": 2, // Number of unread notifications.
  "LastUnreadNotificationIndex": 31147, // Index of the last read notification.
  "UpdateMetadata": false // If true, the frontend should make a call to /api/v0/set-notification-metadata
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

<table><thead><tr><th width="283.3333333333333">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>NotificationsCount</td><td>uint64</td><td>Number of unread notifications</td></tr><tr><td>LastUnreadNotificationIndex</td><td>uint64</td><td>Index of the last read notification</td></tr><tr><td>UpdateMetadata</td><td>Boolean</td><td>if true, the frontend should make a call to <a data-mention href="/pages/Oep1KfRAworddfTr7ITv#set-notification-metadata">/pages/Oep1KfRAworddfTr7ITv#set-notification-metadata</a>to update the state of notifications read</td></tr></tbody></table>

## Set Notification Metadata

<mark style="color:green;">`POST`</mark> `/api/v0/set-notification-metadata`

Update the number of unread notifications, the last notification seen index, and the last unread notification index.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L2050).

Example usages in [diamondapp.com](https://diamondapp.com)'s frontend:\
&#x20; \- Make a request to [Set Notification Metadata](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/backend-api.service.ts#L1691)\
&#x20; \- Use SetNotificationMetadata [when loading the first page of notifications](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/notifications-page/notifications-list/notifications-list.component.ts#L98)

#### Request Body

| Name                                                          | Type   | Description                                                          |
| ------------------------------------------------------------- | ------ | -------------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark>        | String | Public key of the user for whom we are setting notification metadata |
| LastSeenIndex<mark style="color:red;">\*</mark>               | int    | The last notification index the user has seen                        |
| LastUnreadNotificationIndex<mark style="color:red;">\*</mark> | int    | The last notification index that has been scanned                    |
| UnreadNotifications<mark style="color:red;">\*</mark>         | int    | The total count of unread notifications                              |
| JWT<mark style="color:red;">\*</mark>                         | String | JSON web token authenticating user                                   |

{% tabs %}
{% tab title="200: OK Successfully updated notification metadata for user" %}
No response body
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# NFT Endpoints

Description of endpoints used to get data related to posts on the DeSo blockchain

Please make sure you've read [Data: API](/deso-backend/api) so you are familiar with the following types referenced in this documentation:

* [Data: API](/deso-backend/api#profileentryresponse)
* [Data: API](/deso-backend/api#postentryresponse)
* [Data: API](/deso-backend/api#balanceentryresponse)
* [Data: API](/deso-backend/api#nftentryresponse)
* [Data: API](/deso-backend/api#nftcollectionresponse)

## Get NFTs For User

<mark style="color:green;">`POST`</mark> `/api/v0/get-nfts-for-user`

Get NFTs that a user owns, optionally filtering on for-sale status and pending (NFT transferred) status.&#x20;

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/nft.go#L1024).

Example usages in frontend:\
&#x20; \- Make request to [Get NFTs For User](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L980)\
&#x20; \- Use GetNFTsForUser to [get NFTs to display in a gallery on a user's profile](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/creator-profile-page/creator-profile-nfts/creator-profile-nfts.component.ts#L126)

#### Request Body

| Name                                                       | Type    | Description                                                                                                                                                                                                                                                                                                                |
| ---------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String  | Public key for user who owns NFTs                                                                                                                                                                                                                                                                                          |
| ReaderPublicKeyBase58Check                                 | String  | Public key of the reader                                                                                                                                                                                                                                                                                                   |
| IsForSale                                                  | Boolean | <p>  - If true, only return NFTs that are for sale. </p><p>  - If false, only return NFTs that are not for sale.</p><p>  - If not provided, return NFTs regardless of for sale status</p>                                                                                                                                  |
| IsPending                                                  | Boolean | <p>  - If IsForSale is provided, this value is ignored.</p><p>  - Otherwise, if true, only return NFTs that are pending acceptance (NFTs that have been transferred but not accepted).</p><p>  - If false, only return NFTs that are not pending acceptance. If not provided, return NFTs regardless of pending status</p> |

{% tabs %}
{% tab title="200: OK Successfully retrieved the requested NFTs owned by the provided user" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "NFTsMap": { // Map of Post Hash Hex to an object containing a PostEntryResponse AND an NFTEntryResponse.
    "4bd205ec36bb13e76620b48ffc601340562c3ad7fa61b5343f0d9edc6ff6e2f8": {
      "PostEntryResponse": <PostEntryesponse>, // PostEntryResponse of the post that is an NFT owned by UserPublicKeyBase58Check
      "NFTEntryResponses": [<NFTEntryResponse>, <NFTEntryResponse>]// NFTEntryResponses describe the serial numbers of this NFT. There may be multiple for a given post if a user owns multiple NFTs
    },
  }
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get NFT Bids For User

<mark style="color:green;">`POST`</mark> `/api/v0/get-nft-bids-for-user`

Get active bids for a user.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/nft.go#L927).

Example usages in frontend:\
&#x20; \- Make request to [Get NFT Bids For User](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L993)\
&#x20; \- Use GetNFTBidsForUser to [show a user their outstanding bids when they view their own profile](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/creator-profile-page/creator-profile-nfts/creator-profile-nfts.component.ts#L98)

#### Request Body

| Name                                                       | Type   | Description                                    |
| ---------------------------------------------------------- | ------ | ---------------------------------------------- |
| UserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key for user whose bids we want to find |
| ReaderPublicKeyBase58Check                                 | String | Public key of the reader                       |

{% tabs %}
{% tab title="200: OK Successfully retrieved all NFT bids for a given user" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
   {
  "NFTBidEntries": [
    {
      "PublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public key of the user who submitted this bid
      "PostHashHex": "43b943880ff21f67b92941553233b9d0e6bcf7c56e9a533416873d4d0798d290", // Hex of Post hash of the post that is an NFT.
      "SerialNumber": 85, // Serial number on which this bid was submitted.
      "BidAmountNanos": 1000000000, // Amount of DeSo bid (in nanos)
      "HighestBidAmountNanos": 1000000000, // Highest bid amount currently on this serial number
      "LowestBidAmountNanos": 0, // Lowest bid amount currently on this serial number
      "BidderBalanceNanos": 5000000000 // DeSo balance of the bidder
    }
  ],
  "PostHashHexToPostEntryResponse": {
    "43b943880ff21f67b92941553233b9d0e6bcf7c56e9a533416873d4d0798d290": <PostEntryResponse>
  },
  "PublicKeyBase58CheckToProfileEntryResponse": {
    "BC1YLgF9Tt85ADrL4QiyX6xSGwGrqFWnLr9b5Mt8hfdk54Tg1JJzi9e": <ProfileEntryResponse>
  }
}

```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get NFT Bids For NFT Post

<mark style="color:green;">`POST`</mark> `/api/v0/get-nft-bids-for-nft-post`

Get all bids for all serial numbers of a given NFT post.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/nft.go#L1113).

Example usages in frontend:\
&#x20; \- Make request to [Get NFT Bids For NFT Post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L969)\
&#x20; \- Use GetNFTBidsForNFTPost to [show all active bids on all serial numbers of an NFT collection](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/nft-post-page/nft-post/nft-post.component.ts#L152)

#### Request Body

| Name                                          | Type   | Description                                      |
| --------------------------------------------- | ------ | ------------------------------------------------ |
| PostHashHex<mark style="color:red;">\*</mark> | String | Hex of Post hash for which we want to fetch bids |
| ReaderPublicKeyBase58Check                    | String | Public key of the reader                         |

{% tabs %}
{% tab title="200: OK Successfully retrieved all bids on all serial numbers for the given post" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "BidEntryResponses": [ // Array of BidEntryResponses which represents all the bids on all serial numbers of NFTs with the provided PostHashHex.
    {
      "PublicKeyBase58Check": "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public key of user who submitted bid
      "ProfileEntryResponse": <ProfileEntryResponse>,  // ProfileEntryResponse of user who submitted bid.
      "SerialNumber": 85, // Serial number on which this bid was submitted.
      "BidAmountNanos": 1000000000, // Amount of DeSo bid (in nanos).
      "BidderBalanceNanos": 5000000000 // DeSo balance of the bidder.
    }
  ],
  "NFTEntryResponses": [<NFTEntryResponse>, <NFTEntryResponse>, ...],// NFT entry responses for each serial number. There will be one for each serial number.
  "PostEntryResponse": <PostEntryResponse> // PostEntryResponse of the post that is an NFT.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get NFT Showcase

<mark style="color:green;">`POST`</mark> `/api/v0/get-nft-showcase`

Get summaries of all NFTs included in the NFT showcase.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/nft.go#L760).

Example usage in frontend:\
&#x20; \- Make request to [Get NFT Showcase](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1004)\
&#x20; \- Use GetNFTShowcase to [fetch all the NFTs to display in the NFT showcase](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/nft-showcase/nft-showcase.component.ts#L39)

#### Request Body

| Name                       | Type   | Description              |
| -------------------------- | ------ | ------------------------ |
| ReaderPublicKeyBase58Check | String | Public key of the reader |

{% tabs %}
{% tab title="200: OK Successfully retrieved NFT Collection Responses for all NFT posts in the current NFT showcase" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "NFTCollections": [<NFTCollectionResponse>, <NFTCollectionResponse>,...]
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

<table><thead><tr><th width="196.33333333333331">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>NFTCollections</td><td><a href="/pages/EUC9yq2qBWPTvVaptiST#nftcollectionresponse">NFTCollectionResponse</a>[]</td><td>Array of <a data-mention href="/pages/EUC9yq2qBWPTvVaptiST#nftcollectionresponse">/pages/EUC9yq2qBWPTvVaptiST#nftcollectionresponse</a>objects representing all the NFTs in the current NFT Showcase</td></tr></tbody></table>

## Get Next NFT Showcase

<mark style="color:green;">`POST`</mark> `/api/v0/get-next-nft-showcase`

Get the time the next NFT showcase drop so it can be advertised to users

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/nft.go#L858).

Example usages in frontend:\
&#x20; \- Make request to [Get Next NFT Showcase](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1015)\
&#x20; \- Use GetNextNFTShowcase to [show users the time at which the next NFT showcase drops](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/feed/feed.component.ts#L105)

{% tabs %}
{% tab title="200: OK Successfully retrieved the timestamp at which the next NFT showcase will drop" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "NextNFTShowcaseTstamp": 109872497124 // Time the next NFT showcase will drop
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

<table><thead><tr><th width="282.89550731953557">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>NextNFTShowcaseTstamp</td><td>uint64</td><td>Time the next NFT showcase will drop</td></tr></tbody></table>

## Get NFT Collection Summary

<mark style="color:green;">`POST`</mark> `/api/v0/get-nft-collection-summary`

Get an [Data: API](/deso-backend/api#nftcollectionresponse) that summarizes a single NFT post

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/nft.go#L1195).

Example usages in frontend:\
&#x20; \- Make request to [Get NFT Collection Summary](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1021)\
&#x20; \- Use GetNFTCollectionSummary to [a summary of the current state of the NFT collection and each serial number](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/place-bid-modal/place-bid-modal.component.ts#L49)

#### Request Body

| Name                                          | Type   | Description                                                                                        |
| --------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------- |
| PostHashHex<mark style="color:red;">\*</mark> | String | Hex of Post hash for which we want to fetch a [Data: API](/deso-backend/api#nftcollectionresponse) |
| ReaderPublicKeyBase58Check                    | String | Public key of the reader                                                                           |

{% tabs %}
{% tab title="200: OK Successfully retrieved the NFT Collection for the requested post" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "NFTCollectionResponse": {
    "ProfileEntryResponse": <ProfileEntryResponse>, // ProfileEntryResponse of the creator of the NFT
    "PostEntryResponse": <PostEntryResponse>, // PostEntryResponse of the post that is an NFT
    "HighestBidAmountNanos": 2000000000, // Highest bid amount currently on any serial number of this Post
    "LowestBidAmountNanos": 0, // Lowest bid amount currently on any serial number of this Post
    "HighestBidAmountNanos": 35000000000, // Highest buy now price currently on any serial number of this Post
    "LowestBidAmountNanos": 0, // Lowest buy now price currently on any serial number of this Post
    "NumCopiesForSale": 1, // Number of serial numbers currently for sale of this NFT post.
    "NumCopiesBuyNow": 1, // Number of serial numbers currently for sale as "Buy Now" NFTs - this means a user can purchase the NFT at the BuyNowPriceNanos without requiring an accept NFT bid transaction from the owner.
    "AvailableSerialNumbers": [15] // Array of integers representing the set of all serial numbers that are for sale of this NFT post.
  },
  SerialNumberToNFTEntryResponse: { // Map of serial number to NFT Entry Response
    1: <NFTEntryResponse>,
    2: <NFTEntryResponse>,
  }
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get NFT Entries For Post Hash

<mark style="color:green;">`POST`</mark> `/api/v0/get-nft-entries-for-nft-post`

Gets an NFTEntryResponse for each serial number of this NFT post.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/nft.go#L1275).

Example usages in frontend:\
&#x20; \- Make request to [Get NFT Entries for Post Hash](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1028)&#x20;

#### Request Body

| Name                                          | Type   | Description                                                                                             |
| --------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------- |
| PostHashHex<mark style="color:red;">\*</mark> | String | Hex of Post hash for which we want to fetch all [Data: API](/deso-backend/api#nftentryresponse) objects |
| ReaderPublicKeyBase58Check                    | String | Public key of the reader                                                                                |

{% tabs %}
{% tab title="200: OK Successfully retrieved NFTEntryResponse objects for all serial numbers of the NFT post" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "NFTEntryResponses": [<NFTEntryResponse>, <NFTEntryResponse>, ...] // There will be one NFT Entry response for each serial number.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

| Name              | Type                                                                      | Description                                                                                                                                                     |
| ----------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| NFTEntryResponses | [Broken mention](broken://pages/EUC9yq2qBWPTvVaptiST#nftentryresponse)\[] | An array of [Broken mention](broken://pages/EUC9yq2qBWPTvVaptiST#nftentryresponse) objects representing the current state of each serial number of the NFT post |


# Social Endpoints

Description of endpoints used to get social data on the DeSo blockchain

Please make sure you've read [Data: API](/deso-backend/api) so you are familiar with the following types referenced in this documentation:

* [Data: API](/deso-backend/api#profileentryresponse)
* [Data: API](/deso-backend/api#postentryresponse)
* [Data: API](/deso-backend/api#balanceentryresponse)
* [Data: API](/deso-backend/api#nftentryresponse)
* [Data: API](/deso-backend/api#nftcollectionresponse)

## Get Hodlers For Public Key

<mark style="color:green;">`POST`</mark> `/api/v0/get-hodlers-for-public-key`

Get [Data: API](/deso-backend/api#balanceentryresponse) objects for users who are holding (or held by) a certain public key's creator coin.\
\
Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/user.go#L1224).

Example usages in frontend:\
&#x20; \- Make request to [Get Hodlers For Public Key](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/backend-api.service.ts#L1366)\
&#x20; \- Use GetHodlersForPublicKey to [show all the users who are holding a creator's coin or a creator's DAO coin](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/creator-profile-page/creator-profile-hodlers/creator-profile-hodlers.component.ts#L37)\
&#x20; \- Use GetHodlersForPublicKey to [see all users who hold your DAO coin](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/dao-coins/dao-coins.component.ts#L112)\
&#x20; \- Use GetHodlersForPublicKey to [see all DAO coins you hold](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/dao-coins/dao-coins.component.ts#L139)

#### Request Body

| Name                     | Type    | Description                                                                                                                   |
| ------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------- |
| PublicKeyBase58Check     | String  | <p>Public key for which you want to fetch hodlings or hodlers<br><br>Required only if Username is not provided</p>            |
| Username                 | String  | <p>Username for which you want to fetch hodlings or hodlers<br><br>Required only if PublicKeyBase58Check is not provided</p>  |
| LastPublicKeyBase58Check | String  | Public key of the last hodler/hodlee from the previous page. Indicates the point at which we want to start returning results. |
| NumToFetch               | uint64  | number of records to fetch                                                                                                    |
| FetchHodlings            | Boolean | If true, fetch balance entries for hodlings of the user instead of balance entries for hodlers of the user's coin             |
| FetchAll                 | Boolean | if true, fetch all results. Supercedes NumToFetch.                                                                            |
| IsDAOCoin                | Boolean | If true, fetch hodlers of DAO coin instead of creator coin                                                                    |

{% tabs %}
{% tab title="200: OK Successfully retrieved BalanceEntryResponses for each user who are holding/are held by the provided public key/username" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
    Hodlers: [<BalanceEntryResponse>, <BalanceEntryResponse>],
    LastPublicKeyBase58Check: "BC1YLianxEsskKYNyL959k6b6UPYtRXfZs4MF3GkbWofdoFQzZCkJRB" 
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

<table><thead><tr><th width="280.3333333333333">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>Hodlers</td><td><a data-mention href="/pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse">/pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse</a>[]</td><td>Array of <a data-mention href="/pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse">/pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse</a> objects representing the users who hold (or are held by) the provided public key or username. Each <a data-mention href="/pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse">/pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse</a> tells you how much that user is holding.</td></tr><tr><td>LastPublicKeyBase58Check</td><td>String</td><td>Public key of the last <a data-mention href="/pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse">/pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse</a>object from this page of results. Used to fetch the next page of results.</td></tr></tbody></table>

## Get Diamonds for Public Key

<mark style="color:green;">`POST`</mark> `/api/v0/get-diamonds-for-public-key`

Get a list of objects representing all the diamonds a user has given or received.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L1304).

Example usages in frontend:\
&#x20; \- Make request to [Get Diamonds For Public Key](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1414)\
&#x20; \- Use GetDiamondsForPublicKey to [show all users who have given a creator a diamond, how many diamonds they've given to that creator, and the highest level of diamond](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/creator-profile-page/creator-diamonds/creator-diamonds.component.ts#L41)

#### Request Body

| Name                                                   | Type    | Description                                                                      |
| ------------------------------------------------------ | ------- | -------------------------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String  | Public key of the user for whom we want to fetch diamonds                        |
| FetchYouDiamonded                                      | Boolean | If true, fetch diamonds this user gave out instead of diamond this user received |

{% tabs %}
{% tab title="200: OK Successfully retrieved diamonds a user gave or received" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
    DiamondSenderSummaryResponses: [
        {
            SenderPublicKeyBase58Check: "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s", // Public Key of the user who sent the diamond
            ReceiverPublicKeyBase58Check: "BC1YLgxLrxvq5mgZUUhJc1gkG6pwrRCTbdT6snwcrsEampjqnSD1vck", // Public key of the user who received the diamond
            TotalDiamonds: 8, // The number of diamonds the sender has sent to the receiver.
            HighestDiamondLevel: 2, // The highest level of diamond the sender has sent to the receiver.
            DiamondLevelMap: { 1: 4, 2: 2 }, // Map of diamond level to the number of times the sender gave that level of diamond to the receiver.
            ProfileEntryResponse: <ProfileEntryResponse>, // If FetchYouDiamonded is true, this will be the profile of the receiver. If false, this will be the profile of the sender.
        },
    ],
    TotalDiamonds: 555 // Total number of diamonds received or given by the profile that matches PublicKeyBase58Check
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Follows Stateless

<mark style="color:green;">`POST`</mark> `/api/v0/get-follows-stateless`

Get followers of a certain user/public key or get users followed by a certain user/public key and the total number of followers/followees.&#x20;

Endpoint implementation in backend.

Example usages in frontend:\
&#x20; \- Make request to [Get Follows Stateless](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1274)\
&#x20; \- Use GetFollows to show [the total number of users following a creator and the total number of users followed by a creator](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/creator-profile-page/creator-profile-top-card/creator-profile-top-card.component.ts#L161)\
&#x20; \- Use GetFollows to [see all users who follow (or alternatively are followed by) a creator](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/manage-follows-page/manage-follows/manage-follows.component.ts#L54)

#### Request Body

| Name                        | Type    | Description                                                                                                                                     |
| --------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| PublicKeyBase58Check        | String  | <p>Public key for which we want to fetch followers or followees<br><br>Required only if Username is not provided</p>                            |
| Username                    | String  | <p>Username for which we want to fetch followers or following<br><br>Required only if PublicKeyBase58Check is not provided</p>                  |
| GetEntriesFollowingUsername | Boolean | <p>  - If true, get entries that are following the specified user.</p><p>  - If false, get entries that are followed by the specified user.</p> |
| LastPublicKeyBase58Check    | String  | Public key of the last follower/followee from the previous page. Indicates the point at which we want to start returning results.               |
| NumToFetch                  | uint64  | number of records to fetch                                                                                                                      |

{% tabs %}
{% tab title="200: OK Successfully retrieved the requested page of followers/followee" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  PublicKeyToProfileEntry: { // Map of public key to ProfileEntryResponse representing followers or followees
    "BC1YLfuD5AGm2guj3q5wF7WGi3jTUzNhHUHc84GtVsk9kHyxbnk5V1H" : <ProfileEntryResponse>
  }, 
  NumFollowers: 17707 // Total number of followers or followees
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Is Following Public Key

<mark style="color:green;">`POST`</mark> `/api/v0/is-following-public-key`

Check if the user is following a public key.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L2669).

#### Request Body

| Name                                                              | Type   | Description                                                         |
| ----------------------------------------------------------------- | ------ | ------------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark>            | String | Public key of the user that may be following                        |
| IsFollowingPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the creator we want to check if the user is following |

{% tabs %}
{% tab title="200: OK Successfully retrieved whether or not the request public key is following IsFollowingPublicKeyBase58Check" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  IsFollowing: true // true if the user is following the IsFollowingPublicKeyBase58Check. Otherwise, false.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

| Name        | Type    | Description                                                                         |
| ----------- | ------- | ----------------------------------------------------------------------------------- |
| IsFollowing | Boolean | true if the user is following the IsFollowingPublicKeyBase58Check. Otherwise, false |

## Is Hodling Public Key

<mark style="color:green;">`POST`</mark> `/api/v0/is-hodling-public-key`

Check if the user holds the creator coin of a public key. If user is holding some amount of creator coin, we return the BalanceEntryResponse representing how much the user holds.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/user.go#L2836).

Example usages in frontend:\
&#x20; \- Make request to [Is Hodling Public Key](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/backend-api.service.ts#L1387)\
&#x20; \- Use IsHodlingPublicKey to [check if a user is a DAO member and can be transferred a DAO coin that is restricted to DAO members only.](https://github.com/deso-protocol/frontend/blob/60cf5571269c01b13da618e214d35d7f2b5614f1/src/app/dao-coins/transfer-dao-coin-modal/transfer-dao-coin-modal.component.ts#L53)

#### Request Body

| Name                                                            | Type    | Description                                                                                  |
| --------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark>          | String  | Public key of the user that may be holding the creator coin of IsHodlingPublicKeyBase58Check |
| IsHodlingPublicKeyBase58Check<mark style="color:red;">\*</mark> | String  | Public key of the creator we want to check that the user is holding                          |
| IsDAOCoin                                                       | Boolean | If true, check if this public key is hodling the DAO coin instead of creator coin            |

{% tabs %}
{% tab title="200: OK Successfully retrieved whether PublicKeyBas58Check is hodling the creator coin or DAO coin of IsHodlingPublicKeyBase58Check" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  IsHodling: true, // true if the user holds the creator coin of IsHodlingPublicKeyBase58Check, Otherwise, false.
  BalanceEntry: <BalanceEntryResponse> // Balance entry that shows the amount of creator coins the user holds.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

| Name         | Type                                                                       | Description                                                                                                                       |
| ------------ | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| IsHodling    | Boolean                                                                    | true if the user holds the creator coin of IsHodlingPublicKeyBase58Check, Otherwise, false.                                       |
| BalanceEntry | [Broken mention](broken://pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse) | [Broken mention](broken://pages/EUC9yq2qBWPTvVaptiST#balanceentryresponse) that shows the amount of creator coins the user holds. |


# Referral Endpoints

Description of endpoints used to get referral data

Please make sure you've read [Data: API](/deso-backend/api) so you are familiar with the following types referenced in this documentation:

* [Data: API](/deso-backend/api#profileentryresponse)
* [Data: API](/deso-backend/api#postentryresponse)
* [Data: API](/deso-backend/api#balanceentryresponse)
* [Data: API](/deso-backend/api#nftentryresponse)
* [Data: API](/deso-backend/api#nftcollectionresponse)

## Get Referral Info For User

<mark style="color:green;">`POST`</mark> `/api/v0/get-referral-info-for-user`

Gets all data about all referral codes for this owner, including users referred by this code.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/referrals.go#L23).

Example usages in frontend:\
&#x20; \- Make request to [Get Referral Info For User](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L2073)\
&#x20; \- Use GetReferralInfoForUser to [fetch the current state of all referral links for a user upon login](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/global-vars.service.ts#L328)

#### Request Body

| Name                                                   | Type   | Description                        |
| ------------------------------------------------------ | ------ | ---------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | user public key                    |
| JWT<mark style="color:red;">\*</mark>                  | String | JSON web token authenticating user |

{% tabs %}
{% tab title="200: OK Successfully retrieved information about all referral codes a given user has" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "ReferralInfoResponses": [{
      "IsActive": true, // If true, this referral code is still valid. If false, this referral code is not valid anymore.
      "ReferredUsers": [<ProfileEntryResponse>, <ProfileEntryResponse>...], // An array of ProfileEntryResponses representing the list of all users who successfully signed up with this referral code.
      "Info": {
        "ReferralHashBase58": "9diWfRVk", // Referral code
        "ReferrerPKID": [3, 35, 87, 246, 229, 114, 151, 131, 149, 22, 174, 63, 215, 30, 118, 206, 71, 228, 63, 136, 30, 139, 232, 104, 119, 240, 14, 196, 86, 89, 75, 16, 201], // PKID of the user who is the referrer for this code. PKID is a unique identity for a user - a user's PKID stays the same even if they have their identity swapped. This field is not particularly useful in this format for frontend consumption.
        "ReferrerAmountUSDCents": 500, // Amount referrer will receive in USD cents for a successful referral. Upon a successful referral, the referrer will receive the DeSo equivalent of $5 in this example. 
        "ReferreeAmountUSDCents": 2500, // Amount the user who was referred will receive in USD cents for a successful referral. Upon a successful referral, the user who signed up with this code will receive $25 in this example.
        "MaxReferrals": 10, // Maximum number of users that can be referred by this code. Note if this value is 0, there is no limit on the number of referrals
        "RequiresJumio": true, // Not implemented, but in a future state, there may be support for referral bonuses without going through the Jumio verification flow.
        "NumJumioAttempts": 100, // Number of times users have tried to sign up with this referral code and entered the Jumio verification flow
        "NumJumioSuccesses": 90, // Number of times users have successfully completed the Jumio verification flow with this referral code
        "TotalReferrals": 90, // Number of users who have been succesfully referred by this code
        "TotalRefererrerDeSoNanos": 900000, // Total amount of DeSo the referrer received from sign-ups with this referral code
        "TotalRefereeDeSoNanos": 180000, // Total amount of DeSo received across all users who have signed up with referral code.
        "DateCreatedTStampNanos": 9127398712983, // Timestamp of creation of this referral code
      }
    }]
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get Referral Info For Referral Hash

<mark style="color:green;">`POST`</mark> `/api/v0/get-referral-info-for-referral-hash`

Gets a summary of the current state of a single referral code. This is useful when a user arrives at your site with a referral code. It allows you to tell if the referral code is still valid and how much the user would receive if they signed up.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/referrals.go#L77).

Example usages in frontend:\
&#x20; \- Make request to [Get Referral Info For Referral Hash](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L2079)\
&#x20; \- Use GetReferralInfoForReferralHash to [show a new user the amount of money they would receive as a sign-up bonus with this referral code](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/global-vars.service.ts#L1184)

#### Request Body

| Name                                           | Type   | Description   |
| ---------------------------------------------- | ------ | ------------- |
| ReferralHash<mark style="color:red;">\*</mark> | String | referral code |

{% tabs %}
{% tab title="200: OK Successfully retrieved referral info about the provided referral hash" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "ReferralInfoResponse": {
    "IsActive": true, // If true, this referral code is still valid
    "Info": {
      "ReferralHashBase58": "9diWfRVk", // Referral code
      "ReferreeAmountUSDCents": 2500, // Amount the user who was referred will receive in USD cents for a successful referral. Upon a successful referral, the user who signed up with this code will receive $25 in this example.
      "MaxReferrals": 10, // Maximum number of users that can be referred by this code. Note if this value is 0, there is no limit on the number of referrals
      "TotalReferrals": 90, // Number of users who have been succesfully referred by this code
    }
  },
  "CountrySignUpBonus": { // The CountrySignUpBonus object is based on the IP from which the request is made.
    "AllowCustomReferralAmount": true, // If true, referee amount specified in referral code will be paid to users who sign up with IDs from this country. If false, ReferralAmountOverrideUSDCents will be paid to users who sign up with IDs from this country.
    "ReferralAmountOverrideUSDCents": 100, // Amount all referees will be paid when signing up from this country if AllowCustomReferralAmount is false.
    "AllowCustomKickbackAmount": false, // If true, referrer amount specified in referral code will be paid as a kickback to users who gave out referral code that a user signed up with IDs from this country. If false, KickbackAmountOverrideUSDCents will be paid as a kickback to referrers when a user signs up with an ID from this country.
    "KickbackAmountOverrideUSDCents": 0, // Amount all referrers will be paid when a referee signs up from this country if AllowCustomKickbackAmount is false.
  }
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}


# Tutorial Endpoints

Description of endpoints used to get data related to tutorials on the DeSo blockchain

Please make sure you've read [Data: API](/deso-backend/api) so you are familiar with the following types referenced in this documentation:

* [Data: API](/deso-backend/api#profileentryresponse)
* [Data: API](/deso-backend/api#postentryresponse)
* [Data: API](/deso-backend/api#balanceentryresponse)
* [Data: API](/deso-backend/api#nftentryresponse)
* [Data: API](/deso-backend/api#nftcollectionresponse)

## Get Tutorial Creators

<mark style="color:green;">`POST`</mark> `POST /api/v0/get-tutorial-creators`

Get the well-known and up-and-coming creators featured in the Buy a Creator step of the tutorial. Creators who have a founder's reward greater than 10% are excluded here.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/tutorial.go#L32).

Example usage in frontend:\
&#x20; \- Make request to [Get Tutorial Creators](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L2107)\
&#x20; \- Use GetTutorialCreators to [display creators to the user when they are prompted to buy well-known or up-and-coming creators in the tutorial](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/tutorial/buy-creator-coins-tutorial-page/buy-creator-coins-tutorial/buy-creator-coins-tutorial.component.ts#L44)

#### Request Body

| Name                                            | Type | Description                                    |
| ----------------------------------------------- | ---- | ---------------------------------------------- |
| ResponseLimit<mark style="color:red;">\*</mark> | int  | Number of creators to return for each category |

{% tabs %}
{% tab title="200: OK Successfully retrieved tutorial creators" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "WellKnownProfileEntryResponses": [<ProfileEntryResponse>, <ProfileEntryResponse>...], // ProfileEntryResponses of creators randomly selected from the Well-Known category
  "UpAndComingProfileEntryResponses": [<ProfileEntryResponse>, <ProfileEntryResponse>...], // ProfileEntryResponses of creators randomly selected from Up-And-Coming category
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Start Or Skip Tutorial

<mark style="color:green;">`POST`</mark> `/api/v0/start-or-skip-tutorial`

Begin or skip the tutorial.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/tutorial.go#L191).

Example usages in frontend:\
&#x20; \- Make request to [Start Or Skip Tutorial](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L2215)\
&#x20; \- Use StartOrSkipTutorial to [send user into tutorial or skip](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/left-bar/left-bar.component.ts#L109)

#### Request Body

| Name                                                   | Type    | Description                                                                                          |
| ------------------------------------------------------ | ------- | ---------------------------------------------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | string  | Public key of user starting or skipping tutorial                                                     |
| JWT<mark style="color:red;">\*</mark>                  | string  | JSON web token authenticating user                                                                   |
| IsSkip                                                 | boolean | if true, update the user's tutorial status to skipped. Otherwise, set the tutorial status to started |

{% tabs %}
{% tab title="200: OK Successfully triggered start or skip of tutorial" %}
No response body
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Update Tutorial Status

<mark style="color:green;">`POST`</mark> `/api/v0/update-tutorial-status`

Override endpoint to automatically update a user's tutorial status

Valid values for tutorial status are `TutorialStarted`, `TutorialSkipped`, `InvestInOthersBuyComplete`, `InvestInOthersSellComplete`, `TutorialCreateProfileComplete`, `InvestInYourselfComplete`, `FollowCreatorsComplete`, `GiveADiamondComplete`, `TutorialComplete`

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/tutorial.go#L36).

Example usages in [diamondapp.com](https://diamondapp.com)'s frontend:\
&#x20; \- Make request to [Update Tutorial Status](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/backend-api.service.ts#L2275)\
&#x20; \- Use UpdateTutorialStatus to [set the user's tutorial status to the current step in your tutorial](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/trade-creator-page/trade-creator/trade-creator.component.ts#L399)

#### Request Body

| Name                                                   | Type    | Description                                                                              |
| ------------------------------------------------------ | ------- | ---------------------------------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | string  | Public key of user whose tutorial status is being updated                                |
| JWT<mark style="color:red;">\*</mark>                  | string  | JSON web token authenticating user                                                       |
| TutorialStatus<mark style="color:red;">\*</mark>       | string  | Value to be set for user's Tutorial status.                                              |
| CreatorPurchasedInTutorialPublicKey                    | string  | Public key of creator the well-known or up-and-coming the user purchased in the tutorial |
| ClearCreatorCoinPurchasedInTutorial                    | boolean | If true, sets the user's CreatorCoinsPurchasedInTutorial to 0                            |

{% tabs %}
{% tab title="200: OK Successfully updated tutorial" %}
No response body.
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# Meta Data Endpoints

## General Endpoints

### Health Check

```
GET /api/v0/health-check
```

Check if your DeSo node is synced

**Parameters:**

None

**Response:**

If node is synced and received all transactions.

```
200
```

### Get Exchange Rate

```
GET /api/v0/get-exchange-rate
```

Get DeSo exchange rate, total amount of nanos sold, and Bitcoin exchange rate.

**Parameters:**

None

**Response:**

```
{
    "SatoshisPerDeSoExchangeRate":498484,
    "NanosSold":8491518125648433,
    "USDCentsPerBitcoinExchangeRate":3608200
}
```

### Get App State

```
POST /api/v0/get-app-state
```

Get state of DeSo App, such as cost of profile creation and diamond level map. Example use in the [frontend](https://github.com/deso-protocol/frontend/blob/96bdf0c/src/app/backend-api.service.ts#L1106) and endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/47bcc8a/routes/base.go#L86).

**Parameters**

None; however, you need to send an empty JSON `{ }`. Otherwise, you will get 400 - Bad Request. More info on the request [here](https://github.com/deso-protocol/backend/blob/47bcc8a/routes/base.go#L63).

| Name                 | Type   | Description                 |
| -------------------- | ------ | --------------------------- |
| PublicKeyBase58Check | string | (optional) check public key |

**Response**

```
{
    "AmplitudeKey": "",
    "AmplitudeDomain": "api.amplitude.com",
    "MinSatoshisBurnedForProfileCreation": 50000,
    "IsTestnet": false,
    "SupportEmail": "node.admin@protonmail.com",
    "ShowProcessingSpinners": true,
    "HasStarterDeSoSeed": false,
    "HasTwilioAPIKey": false,
    "CreateProfileFeeNanos": 10000000,
    "CompProfileCreation": false,
    "DiamondLevelMap": {
        "1": 50000,
        "2": 500000,
        "3": 5000000,
        "4": 50000000,
        "5": 500000000,
        "6": 5000000000,
        "7": 50000000000,
        "8": 500000000000
    },
    "HasWyreIntegration": false,
    "Password": ""
}
```

##


# Transaction Spending Limits Endpoints

Description of endpoints used to get data related to transaction spending limits on the DeSo blockchain

## Get Transaction Spending Limit Response From Hex

<mark style="color:blue;">`GET`</mark> `/api/v0/get-transaction-spending-limit-response-from-hex/{transactionSpendingLimitHex}`

This endpoint converts a hex string representing a TransactionSpendingLimit object into a client-friendly [Data: API](/deso-backend/api#transactionspendinglimitresponse) object. This is mainly used by identity to parse the transaction spending limit from extra data of an [Derived Keys Transaction API](/deso-backend/construct-transactions/derived-keys-transaction-api#authorize-derived-key) transaction to show the user the permissions they are granting to a derived key.

#### Path Parameters

| Name                                                          | Type   | Description                                        |
| ------------------------------------------------------------- | ------ | -------------------------------------------------- |
| transactionSpendingLimitHex<mark style="color:red;">\*</mark> | String | Hex string representing a TransactionSpendingLimit |

{% tabs %}
{% tab title="200: OK Successfully retrieved a TransactionSpendingLimitResponse from the provided hex" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  <TransactionSpendingLimitResponse> // See the TransactionSpendingLimitResponse description in DataTypes for more details 
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Transaction Spending Limit Hex String

<mark style="color:green;">`POST`</mark> `/api/v0/get-transaction-spending-limit-hex-string`

This endpoint converts a [Data: API](/deso-backend/api#transactionspendinglimitresponse) into a hex string. This is mainly used by identity to convert the object into the form needed to generate an access signature at the [Endpoints](/deso-identity/window-api/endpoints#derive) endpoint.

#### Request Body

| Name                                                       | Type                             | Description                                                                                                        |
| ---------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| TransactionSpendingLimit<mark style="color:red;">\*</mark> | TransactionSpendingLimitResponse | The [Data: API](/deso-backend/api#transactionspendinglimitresponse) for which you wish to retrieve the hex string. |

{% tabs %}
{% tab title="200: OK Successfully retrieve the hex string for the provided TransactionSpendingLimitResponse object" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "HexString": "80d0dbc3f40202020a16010b210000000000000000000000000000000000000000000000000000000000000000000005210210ec74e153aa5c18167dc089030e922cbbfa439acb2051e3f1d4222a33ca417701858af9c3012102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52010a2102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52030221029380f3d890348085a22e07d8daad9f1f3706767bfdd59337641c4d3231046509010421029380f3d890348085a22e07d8daad9f1f3706767bfdd59337641c4d3231046509037b2102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c4500032103f016bef71b72d07ececebc62af189da31c3fa0359d142d732c54c2e2c466915a00e4b0022103f016bef71b72d07ececebc62af189da31c3fa0359d142d732c54c2e2c466915a0198ce0b2103f016bef71b72d07ececebc62af189da31c3fa0359d142d732c54c2e2c466915a028ef0072103f016bef71b72d07ececebc62af189da31c3fa0359d142d732c54c2e2c466915a03904e042102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce5200022102397b1a80eba0a60644650af13c2a6ffdfbbf38830cafc34937a75ddd44b8ce52050a2102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c4500022102aa3dc8d299ea1e4914de66494ed3e16eda9a0d65719d523c1a9a03cbf9f60c45050a0a200000000000000000000000000000000000000000000000000000000000000000000202200000000000000000000000000000000000000000000000000000000000000000000305203e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc000302203e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc010004203e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc020002203e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc03020a203e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc040102203e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc050003203e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc060402203e42215a120a6e9d4848117f5829a2c4d9f692360fd14b78daea483a72d142dc070603"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# User Endpoints

Description of endpoints used to get data related to users and profiles on the DeSo blockchain

Please make sure you've read [Data: API](/deso-backend/api) so you are familiar with the following types referenced in this documentation:

* [Data: API](/deso-backend/api#profileentryresponse)
* [Data: API](/deso-backend/api#postentryresponse)
* [Data: API](/deso-backend/api#balanceentryresponse)
* [Data: API](/deso-backend/api#nftentryresponse)
* [Data: API](/deso-backend/api#nftcollectionresponse)

## Get Users Stateless

<mark style="color:green;">`POST`</mark> `/api/v0/get-users-stateless`

Get information about multiple users. This endpoint is used for retrieving data about a user after they log in, so the UI can adjust to the attributes of the user.

Request contains a list of public keys of users to fetch.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/036804dc7c182305ceb8172cbb92598dcbd4d102/routes/user.go#L40).

Example usages in frontend:\
\- Make request to [Get Users Stateless](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L725)\
\- Use GetUsersStateless to [retrieve data about users upon login](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/app.component.ts#L115)\
\- Use GetUsersStateless to [retrieve profiles for the Bithunt community projects leaderboard](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/lib/services/bithunt/bithunt-service.ts#L77)

#### Request Body

| Name                                                    | Type      | Description                                                                                       |
| ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------- |
| PublicKeysBase58Check<mark style="color:red;">\*</mark> | String\[] | list of public keys                                                                               |
| SkipForLeaderBoard                                      | Boolean   | Skips fetching all attributes other than the ProfileEntryResponse and PublicKeyBase58Check        |
| GetUnminedBalance                                       | Boolean   | If true, get all UTXOs to compute the user's unmined balance. This is slower and not recommended. |

{% tabs %}
{% tab title="200: OK Successfully return all user objects requested, param updater public keys, and the default fee" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  UserList: [
    {
      PublicKeyBase58Check: "BC1YLg3FS19Syz9h6fqErZEtsKkRxBfkzqp75PiGwMUXJ1fLrytRVVk",
      ProfileEntryResponse: <ProfileEntryResponse>,
      Utxos: [], // Deprecated
      BalanceNanos: 100, // User's balance. If SkipForLeaderboard, 0 is always returned. 
      UnminedBalanceNanos: 5, // User's balance in nanos that has not been mined into a block yet. If SkipForLeaderboard, 0 is always returned.
      PublicKeysBase58CheckFollowedByUser: ["BC1YLianxEsskKYNyL959k6b6UPYtRXfZs4MF3GkbWofdoFQzZCkJRB"], // List of public keys followed by this user. If SkipForLeaderboard, an empty array is always returned.
      UsersYouHODL: [<BalanceEntryResponse>, <BalanceEntryResponse>], // Array of Balance entry responses representing this user's creator coin holdings. If SkipForLeaderboard, an empty array is always returned.
      UsersWhoHODLYou: 2, // Count of the number of unique public keys that own this user's creator coin. If SkipForLeaderboard, 0 is always returned.
      HasPhoneNumber: false, // If true, this user has verified their phone number for free DeSo. If SkipForLeaderboard, 0 is always returned.
      CanCreateProfile: true, // If true, this user is able to create a profile. Either they have enough DeSo to cover the create profile fee OR they've verified their phone number OR verified through the Jumio flow. If SkipForLeaderboard, false is always returned.
      BlockedPubKeys: { // BlockedPubKeys is a map with keys representing Public Keys this user has blocked. Values are empty object with no significance. A map is used to improve look up performance. If SkipForLeaderboard, an empty object is always returned.
        "BC1YLiUt3iQG4QY8KHLPXP8LznyFp3k9vFTg2mhhu76d1Uu2WMw9RVY": {},
      },
      HasEmail: true, // If true, the user has provided an email. If SkipForLeaderboard, false is always returned.
      EmailVerified: true, // If true, the user has verified their email address by clicking on a link sent to them. If SkipForLeaderboard, false is always returned. 
      JumioStartTime: 1908230921, // The time at which this user began the Jumio flow. If SkipForLeaderboard, 0 is always returned.
      JumioFinishedTime: 1908230949, // The time at which the user finished the Jumio flow. If SkipForLeaderboard, 0 is always returned.
      JumioVerified: true, // If true, the user successfully completed the Jumio flow and Jumio verified their identity. If SkipForLeaderboard, false is always returned.
      JumioReturned: true, // If true, Jumio's callback after scanning ID has been received. If SkipForLeaderboard, false is always returned.
      IsAdmin: true, // If true, this user is an admin on this node. If SkipForLeaderboard, false is always returned.
      IsSuperAdmin: true, // If true, this user is a superadmin on this node. If SkipForLeaderboard, false is always returned.
      IsBlacklisted: false, // If true, this user is blacklisted on this node. If SkipForLeaderboard, false is always returned.
      IsGraylisted: false, // If true, this user is graylisted on this node. If SkipForLeaderboard, false is always returned.
      TutorialStatus: "TutorialStarted", // Indicates where in the tutorial the user currently is. If SkipForLeaderboard, the empty string is always returned.
      CreatorPurchasedInTutorialUsername: "LazyNina", // Username of the creator the user purchased during the tutorial flow. If SkipForLeaderboard, the empty string is always returned.
      CreatorCoinPurchasedInTutorial: 1823789, // The amount of Lazy Nina creator coins purchased in the tutorial. If SkipForLeaderboard, 0 is always returned.false
      MustCompleteTutorial: true, // If true, the user must finish the tutorial before they are able to perform basic transfers on this node. If SkipForLeaderboard, false is always returned.
    },
  ], 
  DefaultFeeRateNanosPerKB: 100, // The minimum network fee rate in Nanos Per KB. 
  ParamUpdaters: { // Map of Public key to Param Updaters.
    BC1YLfoSyJWKjHGnj5ZqbSokC3LPDNBMDwHX3ehZDCA3HVkFNiPY5cQ: true,
    BC1YLfz4GH3Gfj6dCtBi8bNdNTbTdcibk8iCZS75toUn4UKZaTJnz9y: true,
    BC1YLg3oh6Boj8e2boCo1vQCYHLk1rjsHF6jthBdvSw79bixQvKK6Qa: true,
    BC1YLgD1f7yw7Ue8qQiW7QMBSm6J7fsieK5rRtyxmWqL2Ypra2BAToc: true,
    BC1YLgGLKjuHUFZZQcNYrdWRrHsDKUofd9MSxDq4NY53x7vGt4H32oZ: true,
    BC1YLiXwGTte8oXEEVzm4zqtDpGRx44Y4rqbeFeAs5MnzsmqT5RcqkW: true,
    BC1YLj8UkNMbCsmTUTx5Z2bhtp8q86csDthRmK6zbYstjjbS5eHoGkr: true,
  } 
}5
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Profiles

<mark style="color:green;">`POST`</mark> `/api/v0/get-profiles`

Get user profiles for searching by name or for the creator leaderboard.

Default number of returned profiles is 20.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L599).

Example usages in frontend:\
\- Make request to [Get Profiles](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1118)\
\- Use GetProfiles to [search for users by username](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/search-bar/search-bar.component.ts#L94)\
\- Use GetProfiles to [get profiles for the creator leaderboard](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/creators-leaderboard/creators-leaderboard/creators-leaderboard.component.ts#L59)

#### Request Body

| Name                       | Type    | Description                                                                                                                                                                                                                                                        |
| -------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| PublicKeyBase58Check       | String  | When provided, find the profile that contains the public key. The page of results returned by this endpoint will start at the profile that is next in the ordered list.                                                                                            |
| Username                   | String  | When provided, find the profile that contains this username. The page of results returned by this endpoint will start at the profile that is next in the ordered list.                                                                                             |
| UsernamePrefix             | String  | username prefix. When provided, only return profiles with usernames that match this prefix                                                                                                                                                                         |
| Descripton                 | String  | Deprecated                                                                                                                                                                                                                                                         |
| OrderBy                    | String  | <p>Ordering method to be used on the result set</p><p>\</p><p>\</p><p>Must be one of</p><p><code>newest\_last\_post</code></p><p>,</p><p><code>newest\_last\_comment</code></p><p>, or</p><p><code>influencer\_coin\_price</code></p>                              |
| NumToFetch                 | uint32  | <p>Number of profiles to fetch. Defaults to 20.</p><p>\</p><p>\</p><p>Must be less than 100</p>                                                                                                                                                                    |
| ReaderPublicKeyBase58Check | String  | Reader public key                                                                                                                                                                                                                                                  |
| ModerationType             | String  | <p>empty string, <code>unrestricted</code>, or <code>leaderboard</code>.</p><p>If <code>unrestricted</code>, return all results. If <code>leaderboard</code>, filter out both blacklisted and graylisted users. If empty string, filter out blacklisted users.</p> |
| FetchUsersThatHODL         | Boolean | If single profile is requested, return a list of HODLers                                                                                                                                                                                                           |
| AddGlobalFeedBool          | Boolean | If set to true posts in response will contain boolean if they are in global feed                                                                                                                                                                                   |

{% tabs %}
{% tab title="200: OK List of profiles requested and a NextPublicKey to use to get the next page of results " %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
    ProfilesFound: [<ProfileEntryResponse>, <ProfileEntryResponse>], // Array of ProfileEntryResponse Objects.
    NextPublicKey: "BC1YLianxEsskKYNyL959k6b6UPYtRXfZs4MF3GkbWofdoFQzZCkJRB", // This is the PublicKeyBase58Check needed to fetch the next page of results. 
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Single Profile

<mark style="color:green;">`POST`</mark> `/api/v0/get-single-profile`

Get information about single profile.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L1066).

Example usages in frontend:\
\- Make request to [Get Single Profile](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1144)\
\- Use GetSingleProfile to [get information to display on a user's profile page](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/creator-profile-page/creator-profile-details/creator-profile-details.component.ts#L170)\
\- Use GetSingleProfile to [search for a profile by public key](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/search-bar/search-bar.component.ts#L60)

#### Request Body

| Name                 | Type    | Description                                                                                                                       |
| -------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
| PublicKeyBase58Check | String  | <p>public key of the profile to fetch</p><p>\</p><p>\</p><p>required if Username is not provided</p>                              |
| Username             | String  | <p>username of the profile to fetch</p><p>\</p><p>\</p><p>required if PublicKeyBase58Check is not provided</p>                    |
| NoErrorOnMissing     | Boolean | If true, do not throw a 404 error if there is no profile found. Instead, nil will be return for the Profile in the response body. |

{% tabs %}
{% tab title="200: OK " %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
   Profile: <ProfileEntryResponse>, // ProfileEntryResponse for the username or public key provided.
   IsBlacklisted: false, // If true, this user is blacklisted on this node.
   IsGraylisted: false,  // If true, this user is graylisted on this node.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}

{% tab title="404: Not Found No profile found for the provided username or public key" %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Single Profile Picture

<mark style="color:blue;">`GET`</mark> `/api/v0/get-single-profile-picture/{PublicKeyBase58Check}`

Returns the profile picture of the given public key

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L1011).

Example usage in frontend:\
\- Construct the [Get Single Profile Picture URL](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1158)\
\- Use GetSingleProfilePictureURL to [get the profile picture for a user](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/avatar/avatar.directive.ts#L36)

#### Path Parameters

| Name                                                   | Type   | Description                                                       |
| ------------------------------------------------------ | ------ | ----------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the user for whom we are fetching a profile picture |

#### Query Parameters

| Name     | Type   | Description                                                                                           |
| -------- | ------ | ----------------------------------------------------------------------------------------------------- |
| fallback | String | URL of the image to be used in the event that there is no profile picture for the public key provided |

{% tabs %}
{% tab title="200: OK Profile picture found" %}
Image file of the profile picture is returned
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}

{% tab title="404: Not Found No profile picture found for public key provided" %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get User Global Metadata: Email And Phone Number

<mark style="color:green;">`POST`</mark> `/api/v0/get-user-global-metadata`

Get user metadata such as email and phone.

This endpoint requires a JWT, [which can be retrieved from Identity](/deso-identity/iframe-api/endpoints#jwt).

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L1646).

Example usages in frontend:\
\- Make request to [Get User Global Metadata](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1637)\
\- Use GetUserGlobalMetadata to [fetch email address to display on settings page](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/settings/settings.component.ts#L45)

Note: this data is not stored on-chain.

#### Request Body

| Name                                                       | Type   | Description                        |
| ---------------------------------------------------------- | ------ | ---------------------------------- |
| UserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | user public key                    |
| JWT<mark style="color:red;">\*</mark>                      | String | JSON web token authenticating user |

{% tabs %}
{% tab title="200: OK Successfully retrieved user" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
    Email: "test@test.com",
    PhoneNumber: "123346789"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Update User Global Metadata: Email and State of Messages Read

<mark style="color:green;">`POST`</mark> `/api/v0/update-user-global-metadata`

Update user's email address and the state of messages that have been read.

This endpoint requires a JWT, [which can be retrieved from Identity](/deso-identity/iframe-api/endpoints#jwt).

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L1711).

Example usages in frontend:\
\- Make request to [Update User Global Metadata](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1624)\
\- Use UpdateUserGlobalMetadata to [update email address](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/settings/settings.component.ts#L78)

#### Request Body

| Name                                                       | Type                                   | Description                                                                                                                                                            |
| ---------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String                                 | user public key                                                                                                                                                        |
| JWT<mark style="color:red;">\*</mark>                      | String                                 | JSON web token authenticating user                                                                                                                                     |
| Email                                                      | String                                 | new email address. If provided, an email will be sent to verify this email address                                                                                     |
| MessageReadStateUpdatesByContact                           | Object with string keys and int values | A map with keys that represent public keys that have messaged this user. The values represent the index of the message read in the conversation between the two users. |

{% tabs %}
{% tab title="200: OK Successfully updated user global metadata" %}
No response body
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get User Metadata

<mark style="color:blue;">`GET`</mark> `/api/v0/get-user-metadata/{PublicKeyBase58Check}`

Get user metadata. Typically, this endpoint is used when reaching node.deso.org to get user metadata that should be merged with user metadata from one's local node.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L438).

Example usages in frontend:\
\- Make request to [Get User Metadata](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1667)\
\- Use GetUserMetadata to [get additional data about a user](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/app.component.ts#L117) to merge in with user metadata fetch from local node

#### Path Parameters

| Name                                                   | Type   | Description                                                   |
| ------------------------------------------------------ | ------ | ------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the user for whom we are fetching user metadata |

{% tabs %}
{% tab title="200: OK Successfully retrieved user metadata from this node" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "HasPhoneNumber": false, // Whether the user verified a phone number. Used to know whether to allow user to launch identity to get free DeSo for verifying their phone number 
  "CanCreateProfile": true, // Whether or not this user is capable of creating a profile. Even if a user does not have enough DeSo to create a profile, they may be able to create a profile since it will be comped by the node to which this request was made. Usually profile creation will be comped if a user verified either their phone number or went through the Jumio flow.
  "BlockedPubKeys": { // Map of public keys that are blocked by the user.
    "BC1YLhtBTFXAsKZgoaoYNW8mWAJWdfQjycheAeYjaX46azVrnZfJ94s": {},
  },
  "HasEmail": false, // Whether the user provided an email to the node to which this request was made.
  "EmailVerified": false, // Whether the user verified their email address.
  "JumioFinishedTime": 1629943843752943900, // Time user finished the jumio flow
  "JumioVerified": true, // Whether the user was verified by Jumio
  "JumioReturned": true // Whether Jumio returned a callback for this user.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}

{% tab title="404: Not Found Node does not expose its global state so you are unable to get user metadata from the requested node" %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Delete PII - Personal Identifiable Information

<mark style="color:green;">`POST`</mark> `/api/v0/delete-pii`

Deletes email address and phone number associated with this user from the node's global state.

This endpoint requires a JWT, [which can be retrieved from Identity](/deso-identity/iframe-api/endpoints#jwt).

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L2873).

Example usages in frontend:\
\- Make request to [Delete PII](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1661)\
\- Use DeletePII to [remove user's personal information](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/settings/settings.component.ts#L119) at the user's request

#### Request Body

| Name                                                   | Type   | Description                                    |
| ------------------------------------------------------ | ------ | ---------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | user public key that wants to delete their PII |
| JWT<mark style="color:red;">\*</mark>                  | String | JSON web token authenticating user             |

{% tabs %}
{% tab title="200: OK Successfully deleted personal identifiable information including phone number and email address" %}
No response body
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Block Public Key

<mark style="color:green;">`POST`</mark> `/api/v0/block-public-key`

Block another user. Blocking a user hides that user from everything you see and the blocked user's comments on your posts will be hidden for all other users.

Note: Blocks are not currently stored on chain and thus a block only applies to the node on which a user is blocked.

This endpoint requires a JWT, [which can be retrieved from Identity](/deso-identity/iframe-api/endpoints#jwt).

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L2585).

Example usages in frontend:\
\- Make request to [Block Public Key](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1570)\
\- Use BlockPublicKey to [block a user ](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/creator-profile-page/creator-profile-details/creator-profile-details.component.ts#L136)as described above\
\- Use BlockPublicKey to [unblock a user](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/creator-profile-page/creator-profile-details/creator-profile-details.component.ts#L91)

#### Request Body

| Name                                                        | Type    | Description                        |
| ----------------------------------------------------------- | ------- | ---------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark>      | String  | user public key                    |
| JWT<mark style="color:red;">\*</mark>                       | String  | JSON web token authenticating user |
| BlockPublicKeyBase58Check<mark style="color:red;">\*</mark> | String  | blocked user public key            |
| Unblock                                                     | Boolean | false if block, true if unblock    |

{% tabs %}
{% tab title="200: OK Successfully blocked public key and return all public keys currently blocked by this user" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
    BlockedPublicKeys: {
        "BC1YLhqEhWvNnwW9TBqXURFqwkdpUYKrMVgTHQzopF5rRBDcD1LLSUp": {}, // Every key in the map is a blocked pulic key.
    }
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get User Derived Keys

<mark style="color:green;">`POST`</mark> `/api/v0/get-user-derived-keys`

Get a map of derived public keys to metadata about that derived key for a given master public key.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L2810).

#### Request Body

| Name                                                   | Type   | Description                                        |
| ------------------------------------------------------ | ------ | -------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key for which we want to query derived keys |

{% tabs %}
{% tab title="200: OK Successfully retrieved derived keys for user" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  DerivedKeys: {
    BC1YLhqEhWvNnwW9TBqXURFqwkdpUYKrMVgTHQzopF5rRBDcD1LLSUp: { // Key is a derived key
      OwnerPublicKeyBase58Check: "BC1YLfuD5AGm2guj3q5wF7WGi3jTUzNhHUHc84GtVsk9kHyxbnk5V1H", // Owner of the derived key.
      DerivedPublicKeyBase58Check: "BC1YLhqEhWvNnwW9TBqXURFqwkdpUYKrMVgTHQzopF5rRBDcD1LLSUp", // The derived key itself.
      ExpirationBlock: 1000000, // THe block height at which the derived key expires.
      IsValid: true // If true, this derived key can still perform actions on behalf of the owner.
    } 
  }
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Delete Identities

<mark style="color:green;">`POST`</mark> `/api/v0/delete-identities`

Temporary route to wipe [seedinfo cookies](https://github.com/deso-protocol/docs/blob/main/code/walkthrough.md#seed-creation-and-transaction-construction). This endpoint relies on [identity api](https://github.com/deso-protocol/docs/blob/main/devs/identity-api.md).

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/user.go#L498).

Example usages in frontend:\
\- Make request to [Delete Identities](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L597)\
\- Use DeleteIdentities to [clean up legacy seedinfo storage](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/app.component.ts#L360)

{% tabs %}
{% tab title="200: OK Successfully deleted cookies" %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# Post Endpoints

Description of endpoints used to get data related to posts on the DeSo blockchain

Please make sure you've read [Data: API](/deso-backend/api) so you are familiar with the following types referenced in this documentation:

* [Data: API](/deso-backend/api#profileentryresponse)
* [Data: API](/deso-backend/api#postentryresponse)
* [Data: API](/deso-backend/api#balanceentryresponse)
* [Data: API](/deso-backend/api#nftentryresponse)
* [Data: API](/deso-backend/api#nftcollectionresponse)

## Get Posts Stateless

<mark style="color:green;">`POST`</mark> `/api/v0/get-posts-stateless`

Get Posts Stateless returns an array of posts based on the request body.  This endpoint is used to fetch posts for many different kinds of feeds.

To fetch the global feed, set `GetPostsForGlobalWhitelist` to `true`

To fetch the following feed for a user, set `GetPostsforFollowFeed` to `true`

To fetch the admin view of posts ordered by creator coin price, set `GetPostsByDeSo` to `true` and provide a value for `PostsByDESOMinutesLookback`

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/post.go#L770).

Example usages in frontend:\
&#x20; \- Make request to [Get Posts Stateless](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1066)\
&#x20; \- Use Get Posts Stateless to get the [global feed](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/feed/feed.component.ts#L310)\
&#x20; \- Use Get Posts Stateless to [get the following feed for a user](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/feed/feed.component.ts#L391)\
&#x20; \- Use Get Posts Stateless to [get posts ordered by time for an admin to curate the global feed](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/admin/admin.component.ts#L290)\
&#x20; \- Use Get Posts Stateless to [get posts from user's with the high coin prices in the last hour](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/admin/admin.component.ts#L241)

#### Request Body

| Name                                         | Type    | Description                                                                                                                                                                |
| -------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| GetPostsForFollowFeed                        | Boolean | If true, get posts from creators that the reader follows                                                                                                                   |
| OrderBy                                      | String  | Order the posts by certain attributes                                                                                                                                      |
| NumToFetch<mark style="color:red;">\*</mark> | int     | Maximum Number of posts to return                                                                                                                                          |
| ReaderPublicKeyBase58Check                   | String  | Public key of the reader                                                                                                                                                   |
| PostHashHex                                  | String  | Start paginated look-up of posts after this post hash                                                                                                                      |
| GetPostsForGlobalWhitelist                   | Boolean | If true, get posts for the global feed - these are posts that have been manually selected for the global feed                                                              |
| PostContent                                  | String  | Filters out posts that do not match the text provided in PostContent (case-insensitive)                                                                                    |
| StartTstampSecs                              | uint64  | deprecated                                                                                                                                                                 |
| FetchSubcomments                             | Boolean | If true, fetches comments on comments of each post. Note: not implemented for the following feed                                                                           |
| GetPostsByDESO                               | Boolean | Get posts from the creators with the highest DESO locked within a certain timeframe                                                                                        |
| GetPostsByClout                              | Boolean | deprecated - use GetPostsByDESO instead                                                                                                                                    |
| MediaRequired                                | Boolean | If true, filter out posts that do not have images or video in them                                                                                                         |
| PostsByDESOMinutesLookback                   | uint64  | If GetPostsByDESO is true, get all posts within PostsByDESOMinutesLookback, order them by the creator's DESO locked, and take the top NumToFetch posts. Must be 60 or less |
| AddGlobalFeedBool                            | Boolean | If set to true, then the posts in the response will contain a boolean about whether they're in the global feed                                                             |

{% tabs %}
{% tab title="200: OK Successfully retrieved posts requested" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "PostsFound": [<PostEntryResponse>, <PostEntryResponse>], // Array of PostEntryResponses that were found for the provided request body.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Single Post

<mark style="color:green;">`POST`</mark> `/api/v0/get-single-post`

Gets a single post, optionally including parents and children. This endpoint is used to display a thread view of a post.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/post.go#L968).

Example usages in frontend:\
&#x20; \- Make request to [Get Single Post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1099)\
&#x20; \- Use GetSinglePost to [get a thread view](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/post-thread-page/post-thread/post-thread.component.ts#L289) of a post

#### Request Body

| Name                                           | Type    | Description                                                                                                    |
| ---------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------- |
| PostHashHex<mark style="color:red;">\*</mark>  | String  | Hex of Post Hash to fetch                                                                                      |
| FetchParents                                   | Boolean | if true, fetch all parents of this post, up to 100 parents.                                                    |
| CommentOffset                                  | uint32  | <p>Offset at which to begin result set of comments returned.<br><br>Defaults to 0</p>                          |
| CommentLimit<mark style="color:red;">\*</mark> | uint32  | number of comments to return, starting at CommentOffset                                                        |
| ReaderPublicKeyBase58Check                     | String  | public key of the user reading this single post                                                                |
| AddGlobalFeedBool                              | Boolean | if set to true, then the posts in the response will contain a boolean indicating if they're in the global feed |

{% tabs %}
{% tab title="200: OK Successfully retrieved the single post and any parents or comments" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
 "PostFound": <PostEntryResponse>, // A single PostEntryResponse that optionally contains all children and parent of itself.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Posts For Public Key

<mark style="color:green;">`POST`</mark> `/api/v0/get-posts-for-public-key`

Get posts created by a public key or username. This endpoint is used to populate the posts on a user's profile page.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/post.go#L1321).

Example usages in frontend:\
&#x20; \- Make request to [Get Posts For Public Key](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1168)\
&#x20; \- Use GetPostsForPublicKey to [get posts to display on a user's profile](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/creator-profile-page/creator-profile-posts/creator-profile-posts.component.ts#L51)

#### Request Body

| Name                                         | Type    | Description                                                                                                        |
| -------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------ |
| PublicKeyBase58Check                         | String  | <p>Public key of the user whose posts we will fetch<br><br>Only required if Username is not provided</p>           |
| Username                                     | String  | <p>Username of the user whose posts we will fetch<br><br>Only required if PublicKeyBase58Check is not provided</p> |
| ReaderPublicKeyBase58Check                   | String  | public key of the user reading the posts                                                                           |
| LastPostHashHex                              | String  | Hex of the Post Hash that ended the previous page of results                                                       |
| NumToFetch<mark style="color:red;">\*</mark> | uint64  | Number of posts to fetch                                                                                           |
| MediaRequired                                | Boolean | if true, only return posts that have images, videos, or embed video URLs.                                          |

{% tabs %}
{% tab title="200: OK Successfully retrieved posts for a given public key or username" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "Posts": [<PostEntryResponse>, <PostEntryResponse>], // Array of PostEntryResponses representing a page of results for posts created by the provided public key.
  "LastPostHashHex": "21285bd8c0ed74125cd82a65a74606d8fcb84e309f58bb44b6cb0b76489897b5", //Hex of the last Post Hash in the array of Posts above.  
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Hot Feed

<mark style="color:green;">`POST`</mark> `/api/v0/get-hot-feed`

Get Hot Feed returns a page of Posts that are currently "hot". A post's hotness is determined by the time since the post was created and the number of likes, diamonds, comments, reposts, and quote reposts.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/hot_feed.go#L605).

Example usages in [diamondapp.com](https://diamondapp.com)'s frontend:\
&#x20; \- Make request to [Get Hot Feed](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/backend-api.service.ts#L1153)\
&#x20; \- Use GetHotFeed to [get posts to display to the user in the Hot Feed tab](https://github.com/diamond-app/frontend/blob/735634e38dfa0605035ded19b46b92766ec856c4/src/app/feed/feed.component.ts#L501)

#### Request Body

| Name                       | Type      | Description                                               |
| -------------------------- | --------- | --------------------------------------------------------- |
| ReaderPublicKeyBase58Check | String    | public key of the user reading the posts                  |
| SeenPosts                  | String\[] | A list of posts that have already been seen by the reader |
| ResponseLimit              | uint64    | Number of posts to fetch                                  |

{% tabs %}
{% tab title="200: OK Successfully retrieved posts from the hot feed" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "HotFeedPage": [<PostEntryResponse>, <PostEntryResponse>,...] // Array of PostEntryResponses that represent the next page of the hot feed for the reader
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Diamonded Posts

<mark style="color:green;">`POST`</mark> `/api/v0/get-diamonded-posts`

Get all posts on which sender sent diamonds to the receiver. Posts are sorted by the number of diamonds given from the sender to the receiver and then by timestamp.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/post.go#L1466).

Example usages in frontend:\
&#x20; \- Make request to [Get Diamonded Posts](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1187)\
&#x20; \- Use GetDiamondedPosts to [get posts in which a specific user received diamonds from another specific user](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/diamond-posts-page/diamond-posts/diamond-posts.component.ts#L56). Example on [node.deso.org](https://node.deso.org/u/LazyNina/diamonds/diamondhands)

#### Request Body

| Name                                         | Type    | Description                                                                                                                        |
| -------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| ReceiverPublicKeyBase58Check                 | String  | <p>Public key of the user who received diamonds from sender<br><br>Only required if ReceiverUsername is not provided</p>           |
| ReceiverUsername                             | String  | <p>Username of the user who received diamonds from sender<br><br>Only required if ReceiverPublicKeyBase58Check is not provided</p> |
| SenderPublicKeyBase58Check                   | String  | <p>Public key of the user who sent diamonds to the receiver<br><br>Only required if SenderUsername is not provided</p>             |
| SenderUsername                               | String  | <p>Username of the user who sent diamonds to the receiver<br><br>Only required if SenderPublicKeyBase58Check is not provided</p>   |
| ReaderPublicKeyBase58Check                   | String  | public key of the user reading the posts                                                                                           |
| StartPostHashHex                             | String  | Hex of the first Post Hash to include in this page of results                                                                      |
| NumToFetch<mark style="color:red;">\*</mark> | uint64  | Number of posts to fetch                                                                                                           |
| MediaRequired                                | Boolean | if true, only return posts that have images, videos, or embed video URLs.                                                          |

{% tabs %}
{% tab title="200: OK Successfully retrieved the requested diamonded posts between sender and receiver" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "DiamondedPosts": [<PostEntryResponse>, <PostEntryResponse>] // Array of PostEntryResponses. Each post is a post created by the receiver AND received diamonds from the sender. The DiamondsFromSender attribute is populated in each PostEntryResponse. Posts are ordered by DiamondsFromSender and then by timestamp.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Likes For Post

<mark style="color:green;">`POST`</mark> `/api/v0/get-likes-for-post`

Get Profiles of users who liked a given post.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/post.go#L1629).

Example usages in frontend:\
&#x20; \- Make request to [Get Likes For Post](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/post.go#L1629)\
&#x20; \- Use GetLikesForPosts to [show all users who have liked a po](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/likes-modal/likes-modal.component.ts#L40)

#### Request Body

| Name                                          | Type   | Description                                          |
| --------------------------------------------- | ------ | ---------------------------------------------------- |
| PostHashHex<mark style="color:red;">\*</mark> | String | Hex of Post hash for which we want to retrieve likes |
| Offset<mark style="color:red;">\*</mark>      | uint32 | Position at which to return this page of results     |
| Limit<mark style="color:red;">\*</mark>       | uint32 | Number of profiles to return in this page of results |
| ReaderPublicKeyBase58Check                    | String | Public key of the reader                             |

{% tabs %}
{% tab title="200: OK Successfully retrieved profiles of users who liked a given post" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "Likers": [<ProfileEntryResponse>, <ProfileEntryResponse>] // ProfileEntryResponses for users who liked this post.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Diamonds For Post

<mark style="color:green;">`POST`</mark> `/api/v0/get-diamonds-for-post`

Get Profiles and number of diamonds for users who gave diamonds to a given post

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/post.go#L1750).

Example usages in frontend:\
&#x20; \- Make request to [Get Diamonds For Post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1440)\
&#x20; \- Use GetDiamondsForPosts to [show all users who have diamonded a post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/diamonds-modal/diamonds-modal.component.ts#L40) and how many diamonds the user gave

#### Request Body

| Name                                          | Type   | Description                                                          |
| --------------------------------------------- | ------ | -------------------------------------------------------------------- |
| PostHashHex<mark style="color:red;">\*</mark> | String | Hex of Post hash for which we want to retrieve profiles and diamonds |
| Offset<mark style="color:red;">\*</mark>      | uint32 | Position at which to return this page of results                     |
| Limit<mark style="color:red;">\*</mark>       | uint32 | Number of profiles to return in this page of results                 |
| ReaderPublicKeyBase58Check                    | String | Public key of the reader                                             |

{% tabs %}
{% tab title="200: OK Successfully retrieved profiles and diamond levels of users who gave diamonds the given post" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "DiamondSenders": [
    { 
      "DiamondSenderProfile": <ProfileEntryResponse>, // Profile of the user who gave diamonds to this post
      "DiamondLevel":  2 // Number of diamonds this user gave to this post
    }
  ]
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Reposts For Post

<mark style="color:green;">`POST`</mark> `/api/v0/get-reposts-for-post`

Get Profiles of users who reposted (without a quote) a given post

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/post.go#L1885).

Example usages in frontend:\
&#x20; \- Make request to [Get Reposts For Post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1455)\
&#x20; \- Use GetRepostsForPosts to [show all users who have reposted a post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/reposts-modal/reposts-modal.component.ts#L40)

#### Request Body

| Name                                          | Type   | Description                                              |
| --------------------------------------------- | ------ | -------------------------------------------------------- |
| PostHashHex<mark style="color:red;">\*</mark> | String | Hex of Post hash for which we want to retrieve reposters |
| Offset<mark style="color:red;">\*</mark>      | uint32 | Position at which to return this page of results         |
| Limit<mark style="color:red;">\*</mark>       | uint32 | Number of profiles to return in this page of results     |
| ReaderPublicKeyBase58Check                    | String | Public key of the reader                                 |

{% tabs %}
{% tab title="200: OK Successfully retrieved profiles of users who reposted (without a quote) the provided post" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "Reposters": [<ProfileEntryResponse>, <ProfileEntryResponse>] // Profiles of users who reposted (without a quote) this post.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Get Quote Reposts For Post

<mark style="color:green;">`POST`</mark> `/api/v0/get-quote-reposts-for-post`

Get profiles of users who quote reposted a given post and the content of the quote repost

Endpoint implementation in backend.

Example usages in frontend:\
&#x20; \- Make request to [Get Quote Reposts For Post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L1470)\
&#x20; \- Use GetQuoteRepostsForPost to [show all users who have quoted reposted a post](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/quote-reposts-modal/quote-reposts-modal.component.ts#L40) and what the quote said

#### Request Body

| Name                                          | Type   | Description                                                    |
| --------------------------------------------- | ------ | -------------------------------------------------------------- |
| PostHashHex<mark style="color:red;">\*</mark> | String | Hex of Post hash for which we want to retrieve quote reposters |
| Offset<mark style="color:red;">\*</mark>      | uint32 | Position at which to return this page of results               |
| Limit<mark style="color:red;">\*</mark>       | uint32 | Number of profiles to return in this page of results           |
| ReaderPublicKeyBase58Check                    | String | Public key of the reader                                       |

{% tabs %}
{% tab title="200: OK Successfully retrieved the profiles that quote reposted a given post and the post that is quote reposting" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "QuoteReposts": [<PostEntryResponse>, <PostEntryResponse>] // Post that quote reposted this quote. Each PostEntryResponse will have a ProfileEntryResponse in it.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}
...coming soon! See comments in sample response for descriptions for now.{

```
  "QuoteReposts": [<PostEntryResponse>, <PostEntryResponse>] // Post that quote reposted this quote. Each PostEntryResponse will have a ProfileEntryResponse in it.
}{
  "QuoteReposts": [<PostEntryResponse>, <PostEntryResponse>] // Post that quote reposted this quote. Each PostEntryResponse will have a ProfileEntryResponse in it.
}{
  "QuoteReposts": [<PostEntryResponse>, <PostEntryResponse>] // Post that quote reposted this quote. Each PostEntryResponse will have a ProfileEntryResponse in it.
}{
  "QuoteReposts": [<PostEntryResponse>, <PostEntryResponse>] // Post that quote reposted this quote. Each PostEntryResponse will have a ProfileEntryResponse in it.
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# Messages Endpoints

## Get User Direct Message Threads Ordered by Timestamp

<mark style="color:green;">`POST`</mark> `/api/v0/get-user-dm-threads-ordered-by-timestamp`

Get User Direct Message Threads Ordered by Timestamp returns an array of NewMessageEntryResponse objects for the public key provided in the request body. Each NewMessageEntryResponse object represents the most recent message each in DM conversation a user has. This is useful for showing a list of DM conversations in a user's inbox. The first NewMessageEntryResponse object is the most recent conversation and the last one is the old.

Additionally, a map of public key to [Data: API](/deso-backend/api#profileentryresponse) objects for convenience so you don't need to make an extra request to get profile entry responses for the public keys in the response.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/new_message.go#L459).

#### Request Body

| Name                                                       | Type   | Description                                                           |
| ---------------------------------------------------------- | ------ | --------------------------------------------------------------------- |
| UserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the user for whom we want to fetch all DM conversations |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "MessageThreads": [
    {
      "ChatType": "DM",
      "SenderInfo": {
        "OwnerPublicKeyBase58Check": "tBCKUr3CEsbbg95oH6nauciz3HKxoExX6DgpcFskffGFFXHy5mtrvt",
        "AccessGroupPublicKeyBase58Check": "tBCKVSfJQqcm88YQANuuRDqxHGRZ6pERLmgG2YsbuTJQ66CypHXc2P",
        "AccessGroupKeyName": "default-key"
      },
      "RecipientInfo": {
        "OwnerPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
        "AccessGroupPublicKeyBase58Check": "tBCKVNhD9Kn6WzxT1EdgR3Tf3Yop6CXQSDZnvMLbST6C33DTbsnku4",
        "AccessGroupKeyName": "default-key"
      },
      "MessageInfo": {
        "EncryptedText": "04bec21d8b7ebb8bef474b01adf6a128d4984ba1f2f1f03abeb1612c78477cac0e6bdba24924631a9b4a795d9fd5e82dac8306a0193ec0c8c8c8cee9ca8f8313ec0d393178c1241c00e9aafa380813d0296aefd78eef8eff974dae964b330d3f9e838b1848086c98c1778f434bd6569d7d9de09eb6102fff028f8ca98304a3f7c06833b178f358de11072a05a07f7d77984321",
        "TimestampNanos": 1674622684987966700,
        "TimestampNanosString": "1674622684987966645",
        "ExtraData": null
      }
    }
  ],
  "PublicKeyToProfileEntryResponse": {
    "tBCKUr3CEsbbg95oH6nauciz3HKxoExX6DgpcFskffGFFXHy5mtrvt": null,
    "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2": {
      "PublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
      "Username": "cloutchaser",
      "Description": "",
      "IsHidden": false,
      "IsReserved": false,
      "IsVerified": false,
      "Comments": null,
      "Posts": null,
      "CoinEntry": {
        "CreatorBasisPoints": 10000,
        "DeSoLockedNanos": 1124400018,
        "NumberOfHolders": 1,
        "CoinsInCirculationNanos": 9999331379,
        "CoinWatermarkNanos": 9999331379,
        "BitCloutLockedNanos": 1124400018
      },
      "DAOCoinEntry": {
        "NumberOfHolders": 3,
        "CoinsInCirculationNanos": "0xd96914214a6b400",
        "MintingDisabled": false,
        "TransferRestrictionStatus": "profile_owner_only"
      },
      "CoinPriceDeSoNanos": 337342594,
      "CoinPriceBitCloutNanos": 337342594,
      "UsersThatHODL": null,
      "IsFeaturedTutorialWellKnownCreator": false,
      "IsFeaturedTutorialUpAndComingCreator": false,
      "ExtraData": {
        "BlogSlugMap": "{\"da39a3ee5e\":\"7f9b91cd09ed5cefa0e2bbe2d70698dc665f3d4d31ee2a3a64c91ead3552ed51\"}"
      },
      "DESOBalanceNanos": 5914499708,
      "BestExchangeRateDESOPerDAOCoin": 0
    }
  }
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get Paginated Messages for a Direct Message Thread

<mark style="color:green;">`POST`</mark> `/api/v0/get-paginated-messages-for-dm-thread`

Get Paginated Messages For DM Thread returns an array of NewMessageEntryResponse objects based on the conversation defined in the request body. Each NewMessageEntryResponse object represent a message in the a DM conversation. This is useful for showing all messages in a conversation. This first NewMessageEntryResponse object is the most recent message and the last one is the oldest. This endpoint supports pagination.

Additionally, a map of public key to [Data: API](/deso-backend/api#profileentryresponse) objects for convenience so you don't need to make an extra request to get profile entry responses for the public keys in the response.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/new_message.go#L496).

#### Request Body

| Name                                                                  | Type   | Description                                                                                                                                                                                                                                                                                                                                                                                                       |
| --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UserGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark>  | String | Public key of one of the users in a DM conversation                                                                                                                                                                                                                                                                                                                                                               |
| UserGroupKeyName<mark style="color:red;">\*</mark>                    | String | Access group key name of UserGroupOwnerPublicKeyBase58Check in the DM conversation                                                                                                                                                                                                                                                                                                                                |
| PartyGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the other user in a DM conversation                                                                                                                                                                                                                                                                                                                                                                 |
| PartyGroupKeyName<mark style="color:red;">\*</mark>                   | String | Access group key name of PartyGroupOwnerPublicKeyBase58Check in the DM conversation                                                                                                                                                                                                                                                                                                                               |
| StartTimestampString                                                  | String | <p>String version of a timestamp in nanos. This defines the start point of the page. Messages newer than this timestamp are excluded.</p><p>To get the most recent (but not in the future) messages, set TimestampNanosString to (Date.now()\*1e6).toString()</p><p>To get the next page of messages, take TimestampNanosString from the last NewMessageEntryResponse object in the previous page's response.</p> |
| StartTimestamp                                                        | uint64 | Timestamp in nanos. This is less preferred than passing StartTimestamp string as JSON encoding and decoding can lose precision on these values.                                                                                                                                                                                                                                                                   |
| MaxMessagesToFetch                                                    | int    | Maximum number of messages to fetch. You will always receive this amount of messages or fewer.                                                                                                                                                                                                                                                                                                                    |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "ThreadMessages": [
    {
      "ChatType": "DM",
      "SenderInfo": {
        "OwnerPublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV",
        "AccessGroupPublicKeyBase58Check": "tBCKYe8fNF8pk8Gn3hfD7uYd34a7bz8NVeQmcxaSvqsogtzFkTWEEV",
        "AccessGroupKeyName": "default-key"
      },
      "RecipientInfo": {
        "OwnerPublicKeyBase58Check": "tBCKVv5H1Gz6RTRhjxJwdzcfwfwoUo8b4PYWSKkayG4dy76Jsjt2Ro",
        "AccessGroupPublicKeyBase58Check": "tBCKYdH5NpkaafHkU6foem4qx5rDDd9N8nCXXPUecTfHetEarueJJ6",
        "AccessGroupKeyName": "default-key"
      },
      "MessageInfo": {
        "EncryptedText": "043aaf6732c852ce7b91fbf8556d8a3a4a237852a3550f3e7617b5f5514d8873f152de0fa1157b32f39e42348876852d0ab641f05e1b9775088c635a480952e9ba4b55909cbb0aa073c9bcd09d9c3a4a419cd488d0290dd0b71cf8700bb8728854be062aeafccb5b35a937b48b4e85ead1fec6",
        "TimestampNanos": 1675459724661132500,
        "TimestampNanosString": "1675459724661132641",
        "ExtraData": null
      }
    }
  ],
  "PublicKeyToProfileEntryResponse": {
    "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV": {
      "PublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV",
      "Username": "DeSoMessagingDemo",
      "Description": "The coolest demo on the planet",
      "IsHidden": false,
      "IsReserved": false,
      "IsVerified": false,
      "Comments": null,
      "Posts": null,
      "CoinEntry": {
        "CreatorBasisPoints": 10000,
        "DeSoLockedNanos": 178459749,
        "NumberOfHolders": 3,
        "CoinsInCirculationNanos": 3387141072,
        "CoinWatermarkNanos": 3650090519,
        "BitCloutLockedNanos": 178459749
      },
      "DAOCoinEntry": {
        "NumberOfHolders": 7,
        "CoinsInCirculationNanos": "0x152e2c1689476aa1d680",
        "MintingDisabled": false,
        "TransferRestrictionStatus": "permanently_unrestricted"
      },
      "CoinPriceDeSoNanos": 158062297,
      "CoinPriceBitCloutNanos": 158062297,
      "UsersThatHODL": null,
      "IsFeaturedTutorialWellKnownCreator": false,
      "IsFeaturedTutorialUpAndComingCreator": false,
      "ExtraData": {
        "DAOPublicKeysPurchased": "tBCKWGGQhAwaH1ZhEFbLA1WoaNeErr3qQuqXSw3LZB3R357m1vkS1E,tBCKY3nVGx7M9FT7h1RcpJyWSUpnjEzJQRXSqwAPaqcAF42W9TEwt8,tBCKYdgcgaCgu53xhwT4J2dyfnjP8M1pXogEgeP2rgp2qDhdWhkMpd",
        "DaoDaoURL": "",
        "DerivedPublicKey": "tBCKXpjxNnoe9x6EBVJTdcrTu9NS2mkJ3va7HY9a52CrEPXZQGWfsk",
        "DiscordURL": "",
        "DisplayName": "",
        "FeaturedImageURL": "",
        "LargeProfilePicURL": "",
        "MarkdownDescription": "2320776f6f0a686f6f",
        "TelegramURL": "",
        "TwitterURL": "",
        "WebsiteURL": ""
      },
      "DESOBalanceNanos": 719569565,
      "BestExchangeRateDESOPerDAOCoin": 0.07468259895444361
    },
    "tBCKVv5H1Gz6RTRhjxJwdzcfwfwoUo8b4PYWSKkayG4dy76Jsjt2Ro": {
      "PublicKeyBase58Check": "tBCKVv5H1Gz6RTRhjxJwdzcfwfwoUo8b4PYWSKkayG4dy76Jsjt2Ro",
      "Username": "lazynina",
      "Description": "",
      "IsHidden": false,
      "IsReserved": false,
      "IsVerified": false,
      "Comments": null,
      "Posts": null,
      "CoinEntry": {
        "CreatorBasisPoints": 10000,
        "DeSoLockedNanos": 6834043772,
        "NumberOfHolders": 1,
        "CoinsInCirculationNanos": 5448485463,
        "CoinWatermarkNanos": 5448485463,
        "BitCloutLockedNanos": 6834043772
      },
      "DAOCoinEntry": {
        "NumberOfHolders": 2,
        "CoinsInCirculationNanos": "0x1794bb7c13520200",
        "MintingDisabled": false,
        "TransferRestrictionStatus": "profile_owner_only"
      },
      "CoinPriceDeSoNanos": 3762905032,
      "CoinPriceBitCloutNanos": 3762905032,
      "UsersThatHODL": null,
      "IsFeaturedTutorialWellKnownCreator": false,
      "IsFeaturedTutorialUpAndComingCreator": false,
      "ExtraData": {
        "DAOPublicKeysPurchased": "tBCKY3nVGx7M9FT7h1RcpJyWSUpnjEzJQRXSqwAPaqcAF42W9TEwt8",
        "DerivedPublicKey": "tBCKUoDRjbVj2JMWkMqiDzvbFrSGSdD9nGty4YXsNu4zZW5cySUrbG",
        "DiscordURL": "",
        "DisplayName": "",
        "FeaturedImageURL": "",
        "LargeProfilePicURL": "",
        "MarkdownDescription": "",
        "TelegramURL": "",
        "TwitterURL": "",
        "WebsiteURL": ""
      },
      "DESOBalanceNanos": 16516822968844,
      "BestExchangeRateDESOPerDAOCoin": 0
    }
  }
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get User Group Chat  Threads Ordered by Timestamp

<mark style="color:green;">`POST`</mark> `/api/v0/get-user-group-chat-threads-ordered-by-timestamp`

Get User Group Chat Threads Ordered by Timestamp returns an array of NewMessageEntryResponse objects for the public key provided in the request body. Each NewMessageEntryResponse object represents the most recent message each in a group chat a user has. This is useful for showing a list of group chats in a user's inbox. The first NewMessageEntryResponse object is the most recent conversation and the last one is the oldest.

Additionally, a map of public key to [Data: API](/deso-backend/api#profileentryresponse) objects for convenience so you don't need to make an extra request to get profile entry responses for the public keys in the response.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/new_message.go#L656).

#### Request Body

| Name                                                       | Type   | Description                                                           |
| ---------------------------------------------------------- | ------ | --------------------------------------------------------------------- |
| UserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the user for whom we want to fetch all DM conversations |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "MessageThreads": [
    {
      "ChatType": "GroupChat",
      "SenderInfo": {
        "OwnerPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
        "AccessGroupPublicKeyBase58Check": "tBCKVNhD9Kn6WzxT1EdgR3Tf3Yop6CXQSDZnvMLbST6C33DTbsnku4",
        "AccessGroupKeyName": "default-key"
      },
      "RecipientInfo": {
        "OwnerPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
        "AccessGroupPublicKeyBase58Check": "tBCKWmLgvkMGkMuQ47Jhm8aYMhYMokXpFQTnhqBH7JXQsTuX8AYSs7",
        "AccessGroupKeyName": "a super cool groupchat"
      },
      "MessageInfo": {
        "EncryptedText": "04e8cfc4ebd0f55f612e3779e0a224c702ad89acf33c4499c3f82544f2c0ff295e27dd008f6854abe0c6109ec26b1bbaaedc1e4fa7c7f1dc0dff0cfcc028ddf9fab5e400559e5f280a04442d46168ac67061bcb598a27baa50bf202127397070cbbac68401921777a16017089b6b7f77a01447ff96",
        "TimestampNanos": 1675454352913804800,
        "TimestampNanosString": "1675454352913804789",
        "ExtraData": null
      }
    }
  ],
  "PublicKeyToProfileEntryResponse": {
    "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2": {
      "PublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
      "Username": "cloutchaser",
      "Description": "",
      "IsHidden": false,
      "IsReserved": false,
      "IsVerified": false,
      "Comments": null,
      "Posts": null,
      "CoinEntry": {
        "CreatorBasisPoints": 10000,
        "DeSoLockedNanos": 1124400018,
        "NumberOfHolders": 1,
        "CoinsInCirculationNanos": 9999331379,
        "CoinWatermarkNanos": 9999331379,
        "BitCloutLockedNanos": 1124400018
      },
      "DAOCoinEntry": {
        "NumberOfHolders": 3,
        "CoinsInCirculationNanos": "0xd96914214a6b400",
        "MintingDisabled": false,
        "TransferRestrictionStatus": "profile_owner_only"
      },
      "CoinPriceDeSoNanos": 337342594,
      "CoinPriceBitCloutNanos": 337342594,
      "UsersThatHODL": null,
      "IsFeaturedTutorialWellKnownCreator": false,
      "IsFeaturedTutorialUpAndComingCreator": false,
      "ExtraData": {
        "BlogSlugMap": "{\"da39a3ee5e\":\"7f9b91cd09ed5cefa0e2bbe2d70698dc665f3d4d31ee2a3a64c91ead3552ed51\"}"
      },
      "DESOBalanceNanos": 5914499708,
      "BestExchangeRateDESOPerDAOCoin": 0
    }
  }
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get Paginated Messages For Group Chat Thread

<mark style="color:green;">`POST`</mark> `/api/v0/get-paginated-messages-for-group-chat-thread`

Get Paginated Messages For Group Chat Thread returns an array of NewMessageEntryResponse objects based on the group chat defined in the request body. Each NewMessageEntryResponse object represent a message in the group chat. This is useful for showing all messages in a conversation. This first NewMessageEntryResponse object is the most recent message and the last one is the oldest. This endpoint supports pagination.

Additionally, a map of public key to [Data: API](/deso-backend/api#profileentryresponse) objects for convenience so you don't need to make an extra request to get profile entry responses for the public keys in the response.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/new_message.go#L686).

#### Request Body

| Name                                                       | Type   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ---------------------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the access group owner who owns this group chat.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| AccessGroupKeyName<mark style="color:red;">\*</mark>       | String | Name of the access group for which we want to fetch messages.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| StartTimestampString                                       | String | <p>String version of a timestamp in nanos. This defines the start point of the page. Messages newer than this timestamp are included. To get the most recent messages of the conversation, pass the current timestamp in nanoseconds converted to a string (not formatted as a timestamp).</p><p>To get the most recent (but not in the future) messages, set TimestampNanosString to (Date.now()\*1e6).toString()</p><p>To get the next page of messages, take TimestampNanosString from the last NewMessageEntryResponse object in the previous page's response.</p> |
| StartTimestamp                                             | uint64 | Timestamp in nanos. This is less preferred than passing StartTimestamp string as JSON encoding and decoding can lose precision on these values.                                                                                                                                                                                                                                                                                                                                                                                                                        |
| MaxMessagesToFetch<mark style="color:red;">\*</mark>       | int    | Maximum number of messages to fetch. You will always receive this amount of messages or fewer.                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "GroupChatMessages": [
    {
      "ChatType": "GroupChat",
      "SenderInfo": {
        "OwnerPublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV",
        "AccessGroupPublicKeyBase58Check": "tBCKYe8fNF8pk8Gn3hfD7uYd34a7bz8NVeQmcxaSvqsogtzFkTWEEV",
        "AccessGroupKeyName": "default-key"
      },
      "RecipientInfo": {
        "OwnerPublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV",
        "AccessGroupPublicKeyBase58Check": "tBCKYGaV4ePH88zeVCuj4ywWVN8xf6TDuRThuow4d7dsDYD2A9u8g8",
        "AccessGroupKeyName": "chatdemo"
      },
      "MessageInfo": {
        "EncryptedText": "0481860551243b3524f87a62e9d8704539d20869124f01fccfdc458879f3d42d8db05ac605fda1a2ba6a05d72511758a907c91a7c362359645425bd7e2e4137590a00f7f527ca93744c50b8a8d7b7347753a106e16cf18b47d373533c73c6da84f41b0ad4e59b4bed7d75935a78d320361c3b8bcae24ed743d9549e5a38a2f934007f848db152f55f6a2280a407862cd657f42817928d816f873e4",
        "TimestampNanos": 1675457690291604500,
        "TimestampNanosString": "1675457690291604407",
        "ExtraData": null
      }
    }
  ],
  "PublicKeyToProfileEntryResponse": {
    "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV": {
      "PublicKeyBase58Check": "tBCKVERmG9nZpHTk2AVPqknWc1Mw9HHAnqrTpW1RnXpXMQ4PsQgnmV",
      "Username": "DeSoMessagingDemo",
      "Description": "The coolest demo on the planet",
      "IsHidden": false,
      "IsReserved": false,
      "IsVerified": false,
      "Comments": null,
      "Posts": null,
      "CoinEntry": {
        "CreatorBasisPoints": 10000,
        "DeSoLockedNanos": 178459749,
        "NumberOfHolders": 3,
        "CoinsInCirculationNanos": 3387141072,
        "CoinWatermarkNanos": 3650090519,
        "BitCloutLockedNanos": 178459749
      },
      "DAOCoinEntry": {
        "NumberOfHolders": 7,
        "CoinsInCirculationNanos": "0x152e2c1689476aa1d680",
        "MintingDisabled": false,
        "TransferRestrictionStatus": "permanently_unrestricted"
      },
      "CoinPriceDeSoNanos": 158062297,
      "CoinPriceBitCloutNanos": 158062297,
      "UsersThatHODL": null,
      "IsFeaturedTutorialWellKnownCreator": false,
      "IsFeaturedTutorialUpAndComingCreator": false,
      "ExtraData": {
        "DAOPublicKeysPurchased": "tBCKWGGQhAwaH1ZhEFbLA1WoaNeErr3qQuqXSw3LZB3R357m1vkS1E,tBCKY3nVGx7M9FT7h1RcpJyWSUpnjEzJQRXSqwAPaqcAF42W9TEwt8,tBCKYdgcgaCgu53xhwT4J2dyfnjP8M1pXogEgeP2rgp2qDhdWhkMpd",
        "DaoDaoURL": "",
        "DerivedPublicKey": "tBCKXpjxNnoe9x6EBVJTdcrTu9NS2mkJ3va7HY9a52CrEPXZQGWfsk",
        "DiscordURL": "",
        "DisplayName": "",
        "FeaturedImageURL": "",
        "LargeProfilePicURL": "",
        "MarkdownDescription": "2320776f6f0a686f6f",
        "TelegramURL": "",
        "TwitterURL": "",
        "WebsiteURL": ""
      },
      "DESOBalanceNanos": 719570083,
      "BestExchangeRateDESOPerDAOCoin": 0.07468259895444361
    }
  }
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get All User Message Threads

<mark style="color:green;">`POST`</mark> `/api/v0/get-all-user-message-threads`

Get All User Message Threads Group returns an array of NewMessageEntryResponse objects for the public key provided in the request body. Each NewMessageEntryResponse object represents the most recent message each in a conversation (DM or group chat) a user has. This is useful for showing a list of all conversations in a user's inbox. The first NewMessageEntryResponse object is the most recent conversation and the last one is the oldest.

Additionally, a map of public key to [Data: API](/deso-backend/api#profileentryresponse) objects for convenience so you don't need to make an extra request to get profile entry responses for the public keys in the response.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/new_message.go#L791).

#### Request Body

| Name                                                       | Type   | Description                                                        |
| ---------------------------------------------------------- | ------ | ------------------------------------------------------------------ |
| UserPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the user for whom we want to fetch all conversations |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "MessageThreads": [
    {
      "ChatType": "GroupChat",
      "SenderInfo": {
        "OwnerPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
        "AccessGroupPublicKeyBase58Check": "tBCKVNhD9Kn6WzxT1EdgR3Tf3Yop6CXQSDZnvMLbST6C33DTbsnku4",
        "AccessGroupKeyName": "default-key"
      },
      "RecipientInfo": {
        "OwnerPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
        "AccessGroupPublicKeyBase58Check": "tBCKWmLgvkMGkMuQ47Jhm8aYMhYMokXpFQTnhqBH7JXQsTuX8AYSs7",
        "AccessGroupKeyName": "a super cool groupchat"
      },
      "MessageInfo": {
        "EncryptedText": "04e8cfc4ebd0f55f612e3779e0a224c702ad89acf33c4499c3f82544f2c0ff295e27dd008f6854abe0c6109ec26b1bbaaedc1e4fa7c7f1dc0dff0cfcc028ddf9fab5e400559e5f280a04442d46168ac67061bcb598a27baa50bf202127397070cbbac68401921777a16017089b6b7f77a01447ff96",
        "TimestampNanos": 1675454352913804800,
        "TimestampNanosString": "1675454352913804789",
        "ExtraData": null
      }
    },
    {
      "ChatType": "DM",
      "SenderInfo": {
        "OwnerPublicKeyBase58Check": "tBCKUr3CEsbbg95oH6nauciz3HKxoExX6DgpcFskffGFFXHy5mtrvt",
        "AccessGroupPublicKeyBase58Check": "tBCKVSfJQqcm88YQANuuRDqxHGRZ6pERLmgG2YsbuTJQ66CypHXc2P",
        "AccessGroupKeyName": "default-key"
      },
      "RecipientInfo": {
        "OwnerPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
        "AccessGroupPublicKeyBase58Check": "tBCKVNhD9Kn6WzxT1EdgR3Tf3Yop6CXQSDZnvMLbST6C33DTbsnku4",
        "AccessGroupKeyName": "default-key"
      },
      "MessageInfo": {
        "EncryptedText": "04bec21d8b7ebb8bef474b01adf6a128d4984ba1f2f1f03abeb1612c78477cac0e6bdba24924631a9b4a795d9fd5e82dac8306a0193ec0c8c8c8cee9ca8f8313ec0d393178c1241c00e9aafa380813d0296aefd78eef8eff974dae964b330d3f9e838b1848086c98c1778f434bd6569d7d9de09eb6102fff028f8ca98304a3f7c06833b178f358de11072a05a07f7d77984321",
        "TimestampNanos": 1674622684987966700,
        "TimestampNanosString": "1674622684987966645",
        "ExtraData": null
      }
    }
  ],
  "PublicKeyToProfileEntryResponse": {
    "tBCKUr3CEsbbg95oH6nauciz3HKxoExX6DgpcFskffGFFXHy5mtrvt": null,
    "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2": {
      "PublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
      "Username": "cloutchaser",
      "Description": "",
      "IsHidden": false,
      "IsReserved": false,
      "IsVerified": false,
      "Comments": null,
      "Posts": null,
      "CoinEntry": {
        "CreatorBasisPoints": 10000,
        "DeSoLockedNanos": 1124400018,
        "NumberOfHolders": 1,
        "CoinsInCirculationNanos": 9999331379,
        "CoinWatermarkNanos": 9999331379,
        "BitCloutLockedNanos": 1124400018
      },
      "DAOCoinEntry": {
        "NumberOfHolders": 3,
        "CoinsInCirculationNanos": "0xd96914214a6b400",
        "MintingDisabled": false,
        "TransferRestrictionStatus": "profile_owner_only"
      },
      "CoinPriceDeSoNanos": 337342594,
      "CoinPriceBitCloutNanos": 337342594,
      "UsersThatHODL": null,
      "IsFeaturedTutorialWellKnownCreator": false,
      "IsFeaturedTutorialUpAndComingCreator": false,
      "ExtraData": {
        "BlogSlugMap": "{\"da39a3ee5e\":\"7f9b91cd09ed5cefa0e2bbe2d70698dc665f3d4d31ee2a3a64c91ead3552ed51\"}"
      },
      "DESOBalanceNanos": 5914499708,
      "BestExchangeRateDESOPerDAOCoin": 0
    }
  }
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}


# Access Group Endpoints

## Get All User Access Groups

<mark style="color:green;">`POST`</mark> `/api/v0/get-all-user-access-groups`

Get All User Access Groups gets all Access Group Entry Responses representing all access groups owned by the public key as well as access groups of which the public key is a member.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L546).

#### Request Body

| Name                                                   | Type   | Description                                                      |
| ------------------------------------------------------ | ------ | ---------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the user for whom we want to get all access groups |

{% tabs %}
{% tab title="200: OK " %}

```json5
{
  "AccessGroupsOwned": [
    {
      "AccessGroupOwnerPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
      "AccessGroupKeyName": "",
      "AccessGroupPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
      "ExtraData": null,
      "AccessGroupMemberEntryResponse": null
    },
    {
      "AccessGroupOwnerPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
      "AccessGroupKeyName": "default-key",
      "AccessGroupPublicKeyBase58Check": "tBCKY3eUFE56gCdAA1reHnbnAr9uw69foeW12N1appXDfaHhte1Xia",
      "ExtraData": null,
      "AccessGroupMemberEntryResponse": null
    }
  ],
  "AccessGroupsMember": [
    {
      "AccessGroupOwnerPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
      "AccessGroupKeyName": "a super cool groupchat",
      "AccessGroupPublicKeyBase58Check": "tBCKWmLgvkMGkMuQ47Jhm8aYMhYMokXpFQTnhqBH7JXQsTuX8AYSs7",
      "ExtraData": null,
      "AccessGroupMemberEntryResponse": {
        "AccessGroupMemberPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
        "AccessGroupMemberKeyName": "default-key",
        "EncryptedKey": "04bfaef01cf09ea7698e9f7f3897b7b5d21fc15ae79f36977f46b0fa9244663cded605cd9cbdf35a4b1f2dbdce151e77a9d0cd61e56db26d2086fa99c7940d2ff5296058a1f93b9abe814d3660455737c7d7962d459bc9eedaa9c433184ab810b4bc3e078c21e9c28280914b9289035df61c4ffbe21f9f9a3324588c26441eecfec3268243e50cb661e942a7d5d58748f183064470c783b1f98dee58f1660933e3e4e3bb375bd3ec85875e414a77120a9e",
        "ExtraData": null
      }
    }
  ]
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get All Access Groups Owned

<mark style="color:green;">`POST`</mark> `/api/v0/get-all-user-access-groups-owned`

Get All Access Groups Owned gets all Access Group Entry Responses representing all access groups owned by the public key.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L554).

#### Request Body

| Name                                                   | Type   | Description                                                      |
| ------------------------------------------------------ | ------ | ---------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of user for whom we want to fetch all groups they own |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "AccessGroupsOwned": [
    {
      "AccessGroupOwnerPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
      "AccessGroupKeyName": "",
      "AccessGroupPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
      "ExtraData": null,
      "AccessGroupMemberEntryResponse": null
    },
    {
      "AccessGroupOwnerPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
      "AccessGroupKeyName": "default-key",
      "AccessGroupPublicKeyBase58Check": "tBCKY3eUFE56gCdAA1reHnbnAr9uw69foeW12N1appXDfaHhte1Xia",
      "ExtraData": null,
      "AccessGroupMemberEntryResponse": null
    }
  ]
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get All Access Groups Member Only

<mark style="color:green;">`POST`</mark> `/api/v0/get-all-user-access-groups-member-only`

Get All Access Groups Owned gets all Access Group Entry Responses representing all access groups owned by the public key.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L562).

#### Request Body

| Name                                                   | Type   | Description                                                                        |
| ------------------------------------------------------ | ------ | ---------------------------------------------------------------------------------- |
| PublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of user for whom we want to fetch all groups of which they are a member |

{% tabs %}
{% tab title="200: OK " %}

<pre class="language-javascript"><code class="lang-javascript"><strong>{
</strong><strong>  "AccessGroupsMember": [
</strong>    {
      "AccessGroupOwnerPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
      "AccessGroupKeyName": "a super cool groupchat",
      "AccessGroupPublicKeyBase58Check": "tBCKWmLgvkMGkMuQ47Jhm8aYMhYMokXpFQTnhqBH7JXQsTuX8AYSs7",
      "ExtraData": null,
      "AccessGroupMemberEntryResponse": {
        "AccessGroupMemberPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
        "AccessGroupMemberKeyName": "default-key",
        "EncryptedKey": "04bfaef01cf09ea7698e9f7f3897b7b5d21fc15ae79f36977f46b0fa9244663cded605cd9cbdf35a4b1f2dbdce151e77a9d0cd61e56db26d2086fa99c7940d2ff5296058a1f93b9abe814d3660455737c7d7962d459bc9eedaa9c433184ab810b4bc3e078c21e9c28280914b9289035df61c4ffbe21f9f9a3324588c26441eecfec3268243e50cb661e942a7d5d58748f183064470c783b1f98dee58f1660933e3e4e3bb375bd3ec85875e414a77120a9e",
        "ExtraData": null
      }
    }
  ]
}
</code></pre>

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Check Party Access Groups

<mark style="color:green;">`POST`</mark> `/api/v0/check-party-access-groups`

Check Party Access Groups checks whether both the sender and receiver have the requested access groups. If they do not, it returns the base key.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L633).

#### Request Body

| Name                                                            | Type   | Description                        |
| --------------------------------------------------------------- | ------ | ---------------------------------- |
| SenderPublicKeyBase58Check<mark style="color:red;">\*</mark>    | String | Public key of sender               |
| SenderAccessGroupKeyName<mark style="color:red;">\*</mark>      | String | Access Group Key Name of sender    |
| RecipientPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of recipient            |
| RecipientAccessGroupKeyName<mark style="color:red;">\*</mark>   | String | Access Group Key Name of recipient |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "SenderPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
  "SenderAccessGroupPublicKeyBase58Check": "tBCKY3eUFE56gCdAA1reHnbnAr9uw69foeW12N1appXDfaHhte1Xia",
  "SenderAccessGroupKeyName": "default-key",
  "IsSenderAccessGroupKey": true,
  "RecipientPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
  "RecipientAccessGroupPublicKeyBase58Check": "tBCKVNhD9Kn6WzxT1EdgR3Tf3Yop6CXQSDZnvMLbST6C33DTbsnku4",
  "RecipientAccessGroupKeyName": "default-key",
  "IsRecipientAccessGroupKey": true
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get Access Group Information

<mark style="color:green;">`POST`</mark> `/api/v0/get-access-group-info`

Get Access Group Information gets a single Access Group Entry Response for the access group as defined in the request body.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L762).

#### Request Body

| Name                                                                   | Type   | Description                          |
| ---------------------------------------------------------------------- | ------ | ------------------------------------ |
| AccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the access group owner |
| AccessGroupKeyName<mark style="color:red;">\*</mark>                   | String | Access group key name                |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "AccessGroupOwnerPublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
  "AccessGroupKeyName": "a super cool groupchat",
  "AccessGroupPublicKeyBase58Check": "tBCKWmLgvkMGkMuQ47Jhm8aYMhYMokXpFQTnhqBH7JXQsTuX8AYSs7",
  "ExtraData": null,
  "AccessGroupMemberEntryResponse": null,
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get Access Group Member Information

<mark style="color:green;">`POST`</mark> `/api/v0/get-access-group-member-info`

Get Access Group Member Information gets a single Access Group Member Entry Response for the access group member defined in the request body.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L850).

#### Request Body

| Name                                                                    | Type   | Description                                                                          |
| ----------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------ |
| AccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark>  | String | Public key of the group owner                                                        |
| AccessGroupKeyName<mark style="color:red;">\*</mark>                    | String | Access group key name of the group                                                   |
| AccessGroupMemberPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the member for which we want to fetch a AccessGroupMemberEntryResponse |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "AccessGroupMemberPublicKeyBase58Check": "tBCKVqiE8oRZwcSLBJWN4WR5dSLBEkXZeWv5iqCfp2crknhFB6Fk2n",
  "AccessGroupMemberKeyName": "default-key",
  "EncryptedKey": "04bfaef01cf09ea7698e9f7f3897b7b5d21fc15ae79f36977f46b0fa9244663cded605cd9cbdf35a4b1f2dbdce151e77a9d0cd61e56db26d2086fa99c7940d2ff5296058a1f93b9abe814d3660455737c7d7962d459bc9eedaa9c433184ab810b4bc3e078c21e9c28280914b9289035df61c4ffbe21f9f9a3324588c26441eecfec3268243e50cb661e942a7d5d58748f183064470c783b1f98dee58f1660933e3e4e3bb375bd3ec85875e414a77120a9e",
  "ExtraData": null
}
```

{% endtab %}
{% endtabs %}

## Get Paginated Access Group Members

<mark style="color:green;">`POST`</mark> `/api/v0/get-paginated-access-group-members`

Get Paginated Access Group Members gets a page of Access Group Member Entry responses for the access group defined in the request body. This is useful in identifying all members of a group. A map of public key to profile entry response is provided for convenience.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L932).

#### Request Body

| Name                                                                   | Type   | Description                                                                                                                 |
| ---------------------------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------- |
| AccessGroupOwnerPublicKeyBase58Check<mark style="color:red;">\*</mark> | String | Public key of the group owner                                                                                               |
| AccessGroupKeyName<mark style="color:red;">\*</mark>                   | String | name of the access group                                                                                                    |
| StartingAccessGroupMemberPublicKeyBase58Check                          | String | Public key of the last result from the previous page. To get the first page, exclude this value or make it an empty string. |
| MaxMembersToFetch<mark style="color:red;">\*</mark>                    | int    | Maximum number of members to fetch. You will receive at most this number of members.                                        |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "AccessGroupMembersBase58Check": [
    "tBCKVv5H1Gz6RTRhjxJwdzcfwfwoUo8b4PYWSKkayG4dy76Jsjt2Ro",
    "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2"
  ],
  "PublicKeyToProfileEntryResponse": {
    "tBCKVv5H1Gz6RTRhjxJwdzcfwfwoUo8b4PYWSKkayG4dy76Jsjt2Ro": {
      "PublicKeyBase58Check": "tBCKVv5H1Gz6RTRhjxJwdzcfwfwoUo8b4PYWSKkayG4dy76Jsjt2Ro",
      "Username": "lazynina",
      "Description": "",
      "IsHidden": false,
      "IsReserved": false,
      "IsVerified": false,
      "Comments": null,
      "Posts": null,
      "CoinEntry": {
        "CreatorBasisPoints": 10000,
        "DeSoLockedNanos": 6834043772,
        "NumberOfHolders": 1,
        "CoinsInCirculationNanos": 5448485463,
        "CoinWatermarkNanos": 5448485463,
        "BitCloutLockedNanos": 6834043772
      },
      "DAOCoinEntry": {
        "NumberOfHolders": 2,
        "CoinsInCirculationNanos": "0x1794bb7c13520200",
        "MintingDisabled": false,
        "TransferRestrictionStatus": "profile_owner_only"
      },
      "CoinPriceDeSoNanos": 3762905032,
      "CoinPriceBitCloutNanos": 3762905032,
      "UsersThatHODL": null,
      "IsFeaturedTutorialWellKnownCreator": false,
      "IsFeaturedTutorialUpAndComingCreator": false,
      "ExtraData": {
        "DAOPublicKeysPurchased": "tBCKY3nVGx7M9FT7h1RcpJyWSUpnjEzJQRXSqwAPaqcAF42W9TEwt8",
        "DerivedPublicKey": "tBCKUoDRjbVj2JMWkMqiDzvbFrSGSdD9nGty4YXsNu4zZW5cySUrbG",
        "DiscordURL": "",
        "DisplayName": "",
        "FeaturedImageURL": "",
        "LargeProfilePicURL": "",
        "MarkdownDescription": "",
        "TelegramURL": "",
        "TwitterURL": "",
        "WebsiteURL": ""
      },
      "DESOBalanceNanos": 16516822968844,
      "BestExchangeRateDESOPerDAOCoin": 0
    },
    "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2": {
      "PublicKeyBase58Check": "tBCKW665XZnvVZcCfcEmyeecSZGKAdaxwV2SH9UFab6PpSRikg4EJ2",
      "Username": "cloutchaser",
      "Description": "",
      "IsHidden": false,
      "IsReserved": false,
      "IsVerified": false,
      "Comments": null,
      "Posts": null,
      "CoinEntry": {
        "CreatorBasisPoints": 10000,
        "DeSoLockedNanos": 1124400018,
        "NumberOfHolders": 1,
        "CoinsInCirculationNanos": 9999331379,
        "CoinWatermarkNanos": 9999331379,
        "BitCloutLockedNanos": 1124400018
      },
      "DAOCoinEntry": {
        "NumberOfHolders": 3,
        "CoinsInCirculationNanos": "0xd96914214a6b400",
        "MintingDisabled": false,
        "TransferRestrictionStatus": "profile_owner_only"
      },
      "CoinPriceDeSoNanos": 337342594,
      "CoinPriceBitCloutNanos": 337342594,
      "UsersThatHODL": null,
      "IsFeaturedTutorialWellKnownCreator": false,
      "IsFeaturedTutorialUpAndComingCreator": false,
      "ExtraData": {
        "BlogSlugMap": "{\"da39a3ee5e\":\"7f9b91cd09ed5cefa0e2bbe2d70698dc665f3d4d31ee2a3a64c91ead3552ed51\"}"
      },
      "DESOBalanceNanos": 5914499057,
      "BestExchangeRateDESOPerDAOCoin": 0
    }
  }
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Get Bulk Access Group Entries

<mark style="color:green;">`POST`</mark> `/api/v0/get-bulk-access-group-entries`

Get Bulk Access Group Entries returns an array of AccessGroupEntryResponse objects for the request list of group owner + group key name pairs in the request body.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/v3.1.1/routes/access_group.go#L1051).

#### Request Body

| Name                                                             | Type                             | Description                                                                                                                                                                                                                                                                                                                                                                   |
| ---------------------------------------------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| GroupOwnerAndGroupKeyNamePairs<mark style="color:red;">\*</mark> | GroupOwnerAndGroupKeyNamePair\[] | <p>An array of objects containing the below attributes.</p><p>GroupOwnerPublicKeyBase58Check: the owner of the group</p><p>GroupKeyName: the name of the group</p><p>This endpoint will return the associated AccessGroupEntryResponse for each object. If the AccessGroupEntryResponse is not found, this object will appear in the PairsNotFound array in the response.</p> |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "AccessGroupEntries": [
    {
      "AccessGroupOwnerPublicKeyBase58Check": "tBCKVapwwkTTdgpfEKGphh5bGMvcU9aLJTqssRopKX7wQyzwGvoxGL",
      "AccessGroupKeyName": "default-key",
      "AccessGroupPublicKeyBase58Check": "tBCKWgxWqvmmMF1H9K49onuyp1bcYEs1PqAuCFJJbCg8RJPb4jvBTG",
      "ExtraData": null,
      "AccessGroupMemberEntryResponse": null
    }
  ],
  "PairsNotFound": null
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}


# Transactions: API

Transactions are the building material of every blockchain.

Transactions allow users to submit data to the blockchain which allows user to perform actions such as transferring DeSo, creating posts and profiles, and minting NFTs.

Transactions have three steps in their lifecycle

1. **Construct:** The first step for a developer is to interact with the DeSo Backend API through a transaction construction endpoint to get an unsigned user transaction.\
   &#x20;\
   [Social Transactions API](/deso-backend/construct-transactions/social-transactions-api), [NFT Transactions API](/deso-backend/construct-transactions/nft-transactions-api), [Financial Transactions API](/deso-backend/construct-transactions/financial-transactions-api), and [Derived Keys Transaction API](/deso-backend/construct-transactions/derived-keys-transaction-api) explain the endpoints that will get you an unsigned transaction.<br>
2. **Sign:** The developer will then take the output `TransactionHex` from the construct step's response, which encodes the user transaction, and signs it using DeSo Identity.\
   \
   You can read about signing transactions in the[Endpoints](/deso-identity/iframe-api/endpoints#sign) section of the [Endpoints](/deso-identity/iframe-api/endpoints) documentation.<br>
3. **Broadcast:** The signed transaction will be sent through the `/api/v0/submit-transaction` by the developer so that it can be added to the blockchain ledger.\
   \
   The [#submit-a-transaction](#submit-a-transaction "mention") submit explains how this endpoint works.

You can read more about Transactions in this section of the [Identity documentation. ](/deso-identity/identity/concepts#transactions)

## Submit a transaction

<mark style="color:green;">`POST`</mark> `/api/v0/submit-transaction`

Submit a signed transaction to DeSo blockchain.&#x20;

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L85).

Example usages in frontend:\
&#x20; \- Make request to [Submit Transaction](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L685)\
&#x20; \- Use Submit Transaction [in conjunction with signing transaction](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L483)

#### Request Body

| Name                                             | Type   | Description        |
| ------------------------------------------------ | ------ | ------------------ |
| TransactionHex<mark style="color:red;">\*</mark> | String | Hex of transaction |

{% tabs %}
{% tab title="200: OK " %}
{% tabs %}
{% tab title="Sample Response" %}

```json
{
    "Transaction": {
      "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF", // public key of the transactor
      "TxnTypeJSON": 5, // Integer representing transaction type
      "ExtraData": { // Arbitrary key value map providing metadata about the transaction
        "key": "value"
      },
      "Signature": {
        "R": 981237981749831749879848321, // R attribute of signature
        "S": 843174832748124, // S attribute of signature
      },
      "TxInputs": [{
        "Index": 0, // Index within transaction where the unspent output occurs
        "TxID": [1, 2, 3, ...] // 32 byte transaction id where unspent output occurs 
      }],
      "TxOutputs": [{ 
        "PublicKey": "Aqo9yNKZ6h5JFN5mSU7T4W7amg1lcZ1SPBqaA8v59gxF", // Public key receiving the output
        "AmountNanos": 912739 // Amount of DeSo in the output
      }],
      "TxnMeta": { // Transaction metadata. more details explaining TxnMeta for each transaction type coming soon. 
      ...
      }
    },
    "TxnHashHex": "0f40a5fc7eb991cea55ebece1ec21ee5fb1c4bba537bb76643ee1d31f617bb56",
    "PostEntryResponse": <PostEntryResponse>, // If transaction is a Submit post transaction, include the PostEntryResponse that was created as a result of the transaction.
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

| Name              | Type                                                                                            | Description                                                                                                                                                          |
| ----------------- | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Transaction       | Transaction object                                                                              | transaction object that was broadcast to the DeSo blockchain                                                                                                         |
| PublicKey         | string                                                                                          | <p>Attribute of transaction</p><p></p><p>Public key of transactor</p>                                                                                                |
| TxnTypeJSON       | integer                                                                                         | <p>Attribute of transaction</p><p></p><p>Number representing transaction type</p>                                                                                    |
| ExtraData         | map\[string]string                                                                              | <p>Attribute of transaction</p><p></p><p>Arbitrary key value map providing metadata about the transaction</p>                                                        |
| Signature         | { R: integer, S: integer }                                                                      | <p>Attribute of transaction</p><p></p><p>Signature of transactoin</p>                                                                                                |
| TxInputs          | <p>Array of transaction iputs</p><p></p><p>\[{ Index: integer, TxId: integer\[] }]</p>          | <p>Attribute of transaction </p><p></p><p>Each element represents an input (DeSo being used) in the transaction. </p>                                                |
| TxOutputs         | <p>Array of transaction outputs</p><p></p><p>\[{ PublicKey: string, AmountNanos: integer }]</p> | <p>Attribute of transaction</p><p></p><p>Each element represents an output (DeSo being received) in the transaction</p>                                              |
| TxnMeta           | Transaction Metadata object                                                                     | <p>Attribute of transaction</p><p></p><p>Transaction Metadata descriptions coming soon. Each transaction type has its own transaction metadata object structure.</p> |
| TxnHashHex        | String                                                                                          | Hex of transaction hash broadcasted to the DeSo blockchain                                                                                                           |
| PostEntryResponse | [`PostEntryResponse`](broken://pages/EUC9yq2qBWPTvVaptiST#postentryresponse)                    | If a transaction is a submit post transaction, the `PostEntryResponse` that was created by the transaction is included                                               |
| {% endtab %}      |                                                                                                 |                                                                                                                                                                      |
| {% endtabs %}     |                                                                                                 |                                                                                                                                                                      |
| {% endtab %}      |                                                                                                 |                                                                                                                                                                      |

{% tab title="400: Bad Request Unable to broadcast  transaction to network" %}

{% endtab %}
{% endtabs %}

## Get Transaction

<mark style="color:green;">`POST`</mark> `/api/v0/get-txn`

Check if transaction is currently in mempool. This is particularly useful if you need to wait for a transaction to be broadcasted before submitting a subsequent transaction.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L34).

Example usages in frontend:\
&#x20; \- Make request to [Get Txn](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/backend-api.service.ts#L591)\
&#x20; \- Use Get Txn to [see if a transaction has been broadcast to the network](https://github.com/deso-protocol/frontend/blob/e006beb72867f6d48a78adb1d126c66144a4298c/src/app/app.component.ts#L268)

#### Request Body

| Name                                                 | Type  | Description                                                          |
| ---------------------------------------------------- | ----- | -------------------------------------------------------------------- |
| TransactionHashHex<mark style="color:red;">\*</mark> | Strng | Hex of Transaction hash that we want to check made it to the mempool |

{% tabs %}
{% tab title="200: OK undefined" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
    "TxnFound": true
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

<table><thead><tr><th width="183.59818909503872">Name</th><th width="150.33415912312768">Type</th><th width="214.06091476123234">Description</th><th data-hidden></th></tr></thead><tbody><tr><td>TxnFound</td><td>boolean</td><td>If true, the transaction is currently in the mempool</td><td></td></tr></tbody></table>
{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="400: Bad Request " %}

{% endtab %}
{% endtabs %}

## Append Extra Data

<mark style="color:green;">`POST`</mark> `/api/v0/append-extra-data`

Append custom ExtraData for a given transaction hex. This endpoint is typically used when signing with a derived key.

Note: If you will be using this endpoint, you will need to increase MinFeeRateNanosPerKB to 1500 when using a transaction construction endpoint.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L2314)

#### Request Body

| Name                                             | Type               | Description                                                                                                                                                               |
| ------------------------------------------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TransactionHex<mark style="color:red;">\*</mark> | String             | The hex of the transaction on which extra data will be appended.                                                                                                          |
| ExtraData<mark style="color:red;">\*</mark>      | map\[string]string | Arbitrary key value map that will be merged with any extra data decoded from TransactionHex. Keys from this map will overwrite keys that were decoded from TransactionHex |

{% tabs %}
{% tab title="400: Bad Request " %}

```javascript
{
    // Response
}
```

{% endtab %}

{% tab title="200: OK Hex of transaction with extra data appended" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "TransactionHex": "sometransactionhex"
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

<table><thead><tr><th>Name</th><th>Type</th><th width="179">Description</th></tr></thead><tbody><tr><td>TransactionHex</td><td>string</td><td>hex of transaction with extra data appended</td></tr></tbody></table>
{% endtab %}
{% endtabs %}
{% endtab %}
{% endtabs %}

## Get Transaction Spending

<mark style="color:green;">`POST`</mark> `/api/v0/get-transaction-spending`

Calculates the total transaction spending by subtracting transaction output to sender from transaction inputs. This allows a convenient way to display to users how much they will spend if they submit a given transaction to the network.

Endpoint implementation in [backend](https://github.com/deso-protocol/backend/blob/709cbfbc62cf3a0e6d56c393e555fc277c93fb76/routes/transaction.go#L2384)

Example usages in identity:\
&#x20; \- Make request to [Get Transaction Spending](https://github.com/deso-protocol/identity/blob/9dad527dc46498b9aaa0344abd70dc8895acf246/src/app/backend-api.service.ts#L199)\
&#x20; \- Use Get Transaction Spending to [show user total spending of transaction](https://github.com/deso-protocol/identity/blob/9dad527dc46498b9aaa0344abd70dc8895acf246/src/app/approve/approve.component.ts#L62)

#### Request Body

| Name                                             | Type   | Description                                                      |
| ------------------------------------------------ | ------ | ---------------------------------------------------------------- |
| TransactionHex<mark style="color:red;">\*</mark> | String | The hex of the transaction on which extra data will be appended. |

{% tabs %}
{% tab title="200: OK Total amount spent in the transaction" %}
{% tabs %}
{% tab title="Sample Response" %}

```json5
{
  "TotalSpendingNanos": 1000823987
}
```

{% endtab %}

{% tab title="Response Field Descriptions" %}

| Name               | Type    | Description                                              |
| ------------------ | ------- | -------------------------------------------------------- |
| TotalSpendingNanos | Integer | Total amount spent by the transactor in this transaction |
| {% endtab %}       |         |                                                          |
| {% endtabs %}      |         |                                                          |
| {% endtab %}       |         |                                                          |
| {% endtabs %}      |         |                                                          |


# Exchange Listing: API

The developer community recommends using the open-source Rosetta API implementation, currently used by Coinbase, for integrating DeSo on an exchange: <https://github.com/deso-protocol/rosetta-deso>.\
\
This being said, we provide an alternative set of APIs in this document that may be easier to use, and that the DeSo core team plans to support indefinitely.

Now that anyone in the world can run a DeSo node, we thought we'd democratize and decentralize this effort by publishing a simple public API that any crypto exchange in the world could follow to integrate DeSo.

This guide will cover all of the API endpoints that are needed in order to list DeSo, with detailed descriptions and examples.\
\
This includes:

* Setting up a node.
* Using the Exchange API to create unlimited public/private key pairs.
* Using the Exchange API to check the balance of DeSo public keys.
* Using the Exchange API to transfer DeSo between public keys.
* Using the Exchange API to query for transactions by transaction ID.
* Using the Exchange API to query for transactions by public key.
* Using the Exchange API to query for node sync status.
* Using the Exchange API to query for block information by height or block hash.<br>

The [Quick Start](#quick-start) section provides examples of all of the above using the “curl” command.\
\
The [Full API Guide](#full-api-guide) section provides more detail on each API endpoint shown in the examples.

***Note: This API is strictly for use by exchanges.** The DeSo nodes use in-browser signing such that your seed phrase never leaves your browser (*[*learn more*](/deso-blockchain/privacy-and-security)*). In contrast, exchanges are typically custodial and so some of these endpoints manipulate seeds on behalf of users.*

## Quick Start

### **Generate a Seed Mnemonic**

To get started, you need to generate a standard [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) mnemonic seed that will be used to generate public/private key pairs.\
\
If you don't require that your keys be generated on an air-gapped computer, then you can use the [Diamond](https://diamondapp.com) signup flow to generate your mnemonic.\
\
Note that your seed *never* leaves your browser when you generate it on diamondapp. See [Privacy and Security](/deso-blockchain/privacy-and-security) for more details on this process.

If you need your seed to be generated in an offline fashion, then we recommend that you use [this tool](https://iancoleman.io/bip39/). Either a 12 or 24-word mnemonic should be fine, and standard Bitcoin mnemonics work as well.

What we will use in our examples:

* Mnemonic: *arrive mixture refuse loud people robot dolphin scissors lift curve better demand*
* Passphrase (also known as "ExtraText"): *password*

### Run a Node

All of the commands and examples in this guide will assume that you have a DeSo node running on your local machine.\
\
To set one up, simply follow the instructions in the open-source /run repository. If you run into any trouble, ask for help using [this contact info](/openfund/the-deso-python-sdk/getting-help-from-the-community).

* <https://github.com/deso-protocol/run><br>

Note that the node software is cross-platform and should run on Linux, Mac, and Windows. However, it seems as though people have had the most success with Linux and Mac machines with at least 32GB of RAM and at least 100GB of free disk space.<br>

*NOTE: You must set `READ_ONLY_MODE` to false in* [*dev.env*](https://github.com/deso-protocol/run/blob/190a2380b278689a4db844bb52a31d0450db7d46/dev.env#L265) *in order for some API calls to work. However, at the time of this writing, it is not yet recommended to deploy a production node with `READ_ONLY_MODE` set to false. This should change shortly, though. Keep an eye on the* [*README*](https://github.com/deso-protocol/run/tree/190a2380b278689a4db844bb52a31d0450db7d46) *for updates.*<br>

### Check Node Sync Status

This query will return information about a node’s sync status, among other things. See the [Full API Guide](#full-api-guide) section for more information.

```
curl --header "Content-Type: application/json" --data-raw '{}' \
    http://localhost:17001/api/v1/node-info | python -m json.tool
```

**Notes:**

* We pipe the command into “python -m json.tool” so that it will “pretty print” but that you can delete this part of the command if you don’t have Python installed.<br>
* We are assuming the node is running on the same machine on which we’re doing this query. If the node is running on a different machine then the IP of that machine should be substituted for “localhost.”

### Generate a Public/Private Key Pair

This will generate a public/private key-pair that corresponds to index “0” for this account. Each key-pair will map to an index for a particular seed.\
\
To generate more key-pairs, simply iterate the “Index” parameter:

```
curl --header "Content-Type: application/json" --request POST --data '{
    "Mnemonic":"arrive mixture refuse loud people robot dolphin scissors lift curve better demand",
    "ExtraText":"password",
    "Index": 0
}' http://localhost:17001/api/v1/key-pair  | python -m json.tool
```

**Notes:**

* Under the hood, every public/private key pair maps to derivation path m/44'/0'/0'/0/{index}. \
  \
  **Thus they would be identical to what is generated by any Bitcoin wallet using the same mnemonic, passphrase, and derivation path.**<br>

* The public and private keys returned by this function will be encoded using base58 check encoding described in more detail in the [Full API Guide](#full-api-guide) section for this endpoint. For now, all that you need to know is that you can pass the public/private key strings to other API endpoints to check balances, spend DeSo, etc…<br>
  * DeSo public keys that are encoded with base58 always start with the prefix “BC”. DeSo private keys that are encoded with base58 always start with the prefix “bc” (lower-case).<br>

* Example of DeSo public/private key pair returned by this function. Note that Error being empty string means the endpoint succeeded.<br>
  * ```
    {
        "Error": "",
        "PrivateKeyBase58Check": "bc6EmekhAbzn2V9BchgRLMRMZW1m8mo7kmvdwjZRB5nnKpgQhWSf4",
        "PrivateKeyHex": "423e1f1fe03469e4173f5a0056f468255358f9200fd5acfa7be8185d2fcb98b4",
        "PublicKeyBase58Check": "BC1YLgAJ2kZ7Q4fZp7KzK2Mzr9zyuYPaQ1evEWG4s968sChRBPKbSV1",
        "PublicKeyHex": "024089f4297576513ce07de8190583154c15b8279a586f7d0663ff3c5391351a1e"
    }
    ```

* We pipe the command into “python -m json.tool” so that it will “pretty print” but that you can delete this if you don’t have Python installed.

***Note: This API is strictly for use by exchanges.** The DeSo nodes use a different API that never receives your seed phrase, and your seed phrase never leaves your browser. In contrast, exchanges are typically custodial and so some of these endpoints manipulate seeds on behalf of users.*<br>

### Check Balance of DeSo Public Key

```
curl --header "Content-Type: application/json" --request POST --data '{
    "PublicKeyBase58Check":"BC1YLgAJ2kZ7Q4fZp7KzK2Mzr9zyuYPaQ1evEWG4s968sChRBPKbSV1"
}' http://localhost:17001/api/v1/balance | python -m json.tool
```

**Notes:**

* This will return the balance in “nanos,” where 1 DeSo = 1,000,000,000 “nanos.” For example, if the balance for this public key was “1 DeSo” then this endpoint will return 1,000,000,000 (or 1e9 nanos).<br>
* This endpoint also returns UTXO's, but this likely won't be useful to most node operators.

### Transfer DeSo Using a Public/Private Key-Pair

```
curl --header "Content-Type: application/json" --request POST --data '{
    "SenderPublicKeyBase58Check":"BC1YLgAJ2kZ7Q4fZp7KzK2Mzr9zyuYPaQ1evEWG4s968sChRBPKbSV1", 
    "SenderPrivateKeyBase58Check":"bc6EmekhAbzn2V9BchgRLMRMZW1m8mo7kmvdwjZRB5nnKpgQhWSf4", 
    "RecipientPublicKeyBase58Check":"BC1YLgU67opDhT9bTPsqvue9QmyJLDHRZrSj77cF3P4yYDndmad9Wmx", 
    "AmountNanos": 1000000000
}' http://localhost:17001/api/v1/transfer-deso | python -m json.tool
```

**Notes:**

* This example will fail unless you send DeSo to the `SenderPublicKeyBase58Check`.<br>
  * You can buy DeSo on diamondapp.com and then use the "Send DeSo" page to get some DeSo for testing purposes.<br>
* The amount must be specified in "nanos," where 1 DeSo = 1e9 nanos. This example transfers 1 DeSo from public key `BC1YLgAJ2kZ7Q4fZp7KzK2Mzr9zyuYPaQ1evEWG4s968sChRBPKbSV1` to public key `BC1YLgU67opDhT9bTPsqvue9QmyJLDHRZrSj77cF3P4yYDndmad9Wmx`<br>
  * To do a "dry run" of the transaction without broadcasting it, simply add `DryRun: true` to the params.<br>
* Setting “AmountNanos” to a negative value like -1 will send the maximum amount possible.<br>
  * To implement a UI with a “Max” button, we recommend hitting this endpoint with a negative AmountNanos with DryRun set to true, grabbing the resultant “spend amount,” which will be net of fees, and displaying that to the user.<br>
* This endpoint will return information for the transaction created. See the [Full API Guide](#full-api-guide) section on this endpoint for more information on what is returned.<br>
* A custom “fee rate” can also be set. We recommend providing a value of 1000 for MinFeeRateNanosPerKB. See the [Full API Guide](#full-api-guide) section for this endpoint for more detail on that.

***Note: This API is strictly for use by exchanges**. The diamondapp.com nodes use a different API that never receives your seed phrase, and your seed phrase never leaves your browser. In contrast, exchanges are typically custodial and so some of these endpoints manipulate seeds on behalf of users.*

### Look Up Transactions for a Public Key

```
curl --header "Content-Type: application/json" --request POST --data '{
    "PublicKeyBase58Check":"BC1YLgAJ2kZ7Q4fZp7KzK2Mzr9zyuYPaQ1evEWG4s968sChRBPKbSV1",
    "IDsOnly": true
}' http://localhost:17001/api/v1/transaction-info | python -m json.tool
```

Notes:

* A transaction ID is a sha256 hash of a transaction, encoded using base58 check encoding, that uniquely identifies a transaction.<br>
* This gets all the transaction IDs for a particular public key ordered from oldest to newest.<br>
  * To fetch full transactions rather than just the IDs, simply set `IDsOnly` to `false` rather than `true` or leave it out of the request entirely.<br>
* This endpoint will only work if the node was started with the [TXINDEX flag](https://github.com/deso-protocol/run/blob/190a2380b278689a4db844bb52a31d0450db7d46/dev.env#L123) set to true, which is the default.<br>
  * You must also wait for your `TXINDEX` to generate, which can take a few hours. Grep your logs for UpdateTxIndex to monitor its progress.<br>
* See the [Full API Guide](#full-api-guide) section for this endpoint to see what information will be returned by this endpoint.

### Look Up Transaction Using Transaction ID

Get information for a specific transaction using that transaction’s transaction ID. You can get a transaction ID from other endpoints like the [transfer-deso endpoint](#api-v-1-transfer-deso) described previously.

```
curl --header "Content-Type: application/json" --request POST --data '{
    "TransactionIDBase58Check": "3JuEUE5QSkjyuLwY8WUjS3MRjMbaNEd4nE63VugpU17HMzJW7vbrJP"
}' http://localhost:17001/api/v1/transaction-info | python -m json.tool
```

**Notes:**

* This is the same endpoint as the one used to lookup the transactions for a public key. When a `PublicKeyBase58Check` param is set, the `TransactionIDBase58Check` param is expected to be unset and is ignored.<br>
* This endpoint will only work if the node was started with the [TXINDEX flag](https://github.com/deso-protocol/run/blob/190a2380b278689a4db844bb52a31d0450db7d46/dev.env#L123) set to true, which is the default.<br>
* See the [Full API Guide](#full-api-guide) section for this endpoint to see what information will be returned by this endpoint.

### **Get Block For Block Hash or Height**

This will return all the information associated with the block at height 10715. If the chain is not synced up to this point, an error will be returned.

```
curl --header "Content-Type: application/json" --request POST --data '{
    "Height":10715
}' http://localhost:17001/api/v1/block | python -m json.tool
```

\
Same as the previous example, only queries the block by its hash rather than its height.

```
curl --header "Content-Type: application/json" --request POST --data '{
    "HashHex":"0000000000306a10b85a0bfd801479f1f2227ebaa8bdd5c61da4736dff319362"
}' http://localhost:17001/api/v1/block | python -m json.tool
```

\
For more information, see the [Full API Guide](#full-api-guide) section for these endpoints.<br>

## Full API Guide

***Note: This API is strictly for use by exchanges.** The diamondapp.com nodes use a different API that never receives your seed phrase, and your seed phrase never leaves your browser. In contrast, exchanges are typically custodial and so some of these endpoints manipulate seeds on behalf of users.*

***Note: The dev community is also working to complete an integration with*** [***Rosetta***](https://www.rosetta-api.org) ***that will further build on this API.***

### /api/v1/key-pair

You can generate public/private keypairs with a standard BIP39 mnemonic. Each public/private key pair corresponds to a particular index associated with the mnemonic.\
\
This means that index “5” for a particular mnemonic, for example, will always generate the same public/private key pair. An infinite number of public/private key pairs can thus be generated by iterating an index over a particular mnemonic.

All public/private keys are inter-operable as Bitcoin public/private keys.\
\
Meaning they represent a point on the secp256k1 curve (same as what is used by Bitcoin).

Under the hood, DeSo takes the BIP39 mnemonic and generates the public/private key pairs using the BIP32 derivation path m/44'/0'/0'/0/{index}, where "index" is the index of the public/private key being generated.\
\
This means that DeSo public/private key pair generated by the node will always line up with the public/private key pairs generated by [this Ian Coleman tool](https://iancoleman.io/bip39/).\
\
An engineer can therefore “sanity check” that things are working by generating a mnemonic using diamondapp.com or Ian Coleman, creating a key pair with that mnemonic, and then verifying that the public/private key pairs generated line up with what is shown on diamondapp.com or Ian Coleman.

```
PATH: /api/v1/key-pair
METHOD: POST
POST PARAMS:
    // A BIP39 mnemonic and extra text. Mnemonic can be 12 words or
    // 24 words. ExtraText is optional.
    Mnemonic  string
    ExtraText string
    // The index of the public/private key pair to generate
    Index uint32
RETURNS:
  // Blank if successful. Otherwise, contains a description of the
  // error that occurred.
  Error string
  // The DeSo public key encoded using base58 check encoding with
  // prefix = [3]byte{0x11, 0xc2, 0x0}
  // This public key can be passed in subsequent API calls to check
  // balance, among other things. All encoded DeSo public keys start
  // with the characters “BC”
  PublicKeyBase58Check string
  // The DeSo public key encoded as a plain hex string. This should
  // match the public key with the corresponding index generated by the
  // Ian Coleman tool.
  // This should not be passed to subsequent API calls, it is only provided
  // as a reference, mainly as a sanity-check.
  PublicKeyHex string
  // The DeSo private key encoded using base58 check encoding with
  // prefix = [3]byte{0x4f, 0x6, 0x1b}
  // This private key can be passed in subsequent API calls to spend DeSo,
  // among other things. All DeSo private keys start with
  // the characters “bc”
  PrivateKeyBase58Check string
  // The DeSo private key encoded as a plain hex string. Note that
  // this will not directly match what is produced by the Ian Coleman
  // tool because the tool shows the private key encoded using
  // Bitcoin’s WIF format rather than as raw hex. To convert this raw hex
  // into Bitcoin’s WIF format you can use this simple Python script:
  // https://github.com/geniusprodigy/bitcoin-convertpvk
  // This should not be passed to subsequent API calls. It is provided as
  // a reference, mainly as a sanity-check.
  PrivateKeyHex string
```

### /api/v1/balance

One can check the balance of a particular public key by passing the public key to the following endpoint.

Spent transaction outputs are not returned by this endpoint. \
\
o perform operations on spent transaction outputs, one must use the “transaction-info” endpoint instead.

```
PATH: /api/v1/balance
METHOD: POST
POST PARAMS:
  // A DeSo public key encoded using base58 check encoding (starts
  // with “BC”). When this field is provided, the other params are
  // ignored.
  PublicKeyBase58Check string
  // Only consider UTXOs with greater than or equal to the specified number
  // of confirmations. This defaults to zero, which considers all UTXOs,
  // including those in the mempool.
  Confirmations uint32
RETURNS:
  // Blank if successful. Otherwise, contains a description of the
  // error that occurred.
  Error string
  // The balance of the public key queried in “nanos.” Note 
  // there are 1e9 “nanos” per DeSo, so if the balance were “1 DeSo” then
  // this value would be set to 1e9.
  ConfirmedBalanceNanos int64
  // The unconfirmed balance of the public key queried in “nanos.” This field
  // is set to zero if Confirmations is set to a value greater than zero.
  UnconfirmedBalanceNanos int64
  // DeSo uses a UTXO model similar to Bitcoin. As such, querying
  // the balance returns all of the UTXOs for a particular public key for
  // convenience. Note that a UTXO is simply a reference to a particular
  // output index in a previous transaction
  UTXOs [{
    // A string that uniquely identifies a previous transaction. This is
    // a sha256 hash of the transaction’s information encoded using
    // base58 check encoding. Will be empty string if this UTXO is
    // a block reward.
    TransactionIDBase58Check string
    // The index within this transaction that corresponds to an output
    // spendable by the passed-in public key.
    Index int64
    // The amount that is spendable by this UTXO in “nanos” = 1e9 DeSo.
    AmountNanos uint64
    // The pulic key entitled to spend the amount stored in this UTXO.
    PublicKeyBase58Check string
    // The number of confirmations this UTXO has. Set to zero if the
    // UTXO is unconfirmed.
    Confirmations int64
    // Whether or not this UTXO was a block reward.
    IsBlockReward bool
  }, ... ]
```

### /api/v1/transfer-deso

DeSo can be transferred from one public key to another using this simple API call. To transfer DeSo, one must either provide a public/private key pair.

DeSo recently transitioned from a UTXO model to a balance model and any references to UTXOs in the examples below have been deprecated.

The maximum amount of DeSo can be sent by specifying a negative amount when calling the endpoint.\
\
We recommend running the endpoint once with `DryRun` set to `true`, inspecting the output, and then running it with `DryRun` set to `false`, which will actually broadcast the transaction.

```
PATH: /api/v1/transfer-deso
METHOD: POST
POST PARAMS:
    // A DeSo private key encoded using base58 check encoding (starts
    // with "bc").
    SenderPrivateKeyBase58Check string
    // A DeSo public key encoded using base58 check encoding (starts
    // with “BC”) that will receive the DeSo being sent.
    RecipientPublicKeyBase58Check string
    // The amount of DeSo to send in “nanos.” Note that “1 DeSo” is equal to
    // 1e9 nanos, so to send 1 DeSo, this value would need to be set to 1e9.
    AmountNanos int64
    // The fee rate to use for this transaction. If left unset, a default fee rate
    // will be used. This can be checked using the “DryRun” parameter below. However, 
    // we recommend providing a value of 1000 for this.
    MinFeeRateNanosPerKB int64
    // When set to true, the transaction is returned in the response but not
    // actually broadcast to the network. Useful for testing.
    DryRun bool
RETURNS:
  // Blank if successful. Otherwise, contains a description of the
  // error that occurred.
  Error string
  // The transaction that executes the transfer. Will not be broadcast
  // if DryRun is set to true.
  Transaction {
    // A string that uniquely identifies this transaction. This is a sha256 hash
    // of the transaction’s data encoded using base58 check encoding.
    TransactionIDBase58Check string
    // The raw hex of the transaction data. This can be fully-constructed from
    // the human-readable portions of this object.
    RawTransactionHex string
    // The inputs of this transaction.
    Inputs [{
        // An input in a transaction consists of the transaction ID and
        // the index of the output from that transaction.
        TransactionIDBase58Check string
        Index int64
      }, ... ]
    Outputs [
      // A transaction output is simply a public key and the
      // amount that is being allocated to that public key in
      // “nanos” where 1 DeSo = 1e9 nanos.
      {
        PublicKeyBase58Check string
        AmountNanos int64
      }, ... ]
    // The signature of the transaction in hex format.
    SignatureHex string
    // Will always be “0” for basic transfers
    TransactionType int64
    // Will always be empty for basic transfers
    TransactionMeta {}
    // The hash of the block in which this transaction was mined. If the
    // transaction is unconfirmed, this field will be empty. To look up
    // how many confirmations a transaction has, simply plug this value
    // into the "block" endpoint.
    BlockHashHex string
  }
  TransactionInfo {
    // The sum of the inputs
    TotalInputNanos uint64
    // The amount being sent to the “RecipientPublicKeyBase58Check”
    SpendAmountNanos uint64
    // The amount being returned to the “SenderPublicKeyBase58Check”
    ChangeAmountNanos uint64
    // The total fee and the fee rate (in nanos per KB) that was used for this
    // transaction.
    FeeNanos uint64
    FeeRateNanosPerKB uint64
    // Will match the public keys passed as params. Note that
    // SenderPublicKeyBase58Check receives the change from this transaction.
    SenderPublicKeyBase58Check string
    RecipientPublicKeyBase58Check string
  }
```

### /api/v1/transaction-info

If one has a `TransactionIDBase58Check`, e.g. from calling the “transfer-deso” endpoint, one can get the corresponding human-readable “Transaction object” by passing this transaction id to a node. Note that this endpoint will error if `TXINDEX` is set to false.\
\
If `TXINDEX` was passed to the node but it has not finished syncing the blockchain yet, this endpoint may return incomplete results.\
\
The `/node-info` endpoint can be used to check where a node is in its sync process (generally, syncing takes only a minute or two).

If one has a `PublicKeyBase58Check` (starts with “BC”), one can get all of the TransactionIDs associated with that public key sorted by oldest to newest (this will include transactions where the address is a sender and a receiver).\
\
One can also optionally get the full Transaction objects for all of the transactions in the same call.

```
PATH: /api/v1/transaction-info
METHOD: POST
POST PARAMS:
  // A string that uniquely identifies this transaction. E.g. from a previous
  // call to “transfer-deso”. Ignored when PublicKeyBase58Check is set.
  // When a transaction is looked up using its ID directly, we also scan the
  // mempool for it. This makes it so that a “block explorer” can easily
  // surface transactions associated with a particular ID.
  TransactionIDBase58Check string
  // A DeSo public key encoded using base58 check encoding (starts
  // with “BC”) to get transaction IDs for. When set,
  // TransactionIDBase58Check is ignored.
  PublicKeyBase58Check string
  // Whether or not to return full transaction info or just the TransactionIDHex
  // for each transaction. Full transactions are returned when this is unset.
  IDsOnly bool
RETURNS
  // Blank if successful. Otherwise, contains a description of the
  // error that occurred.
  Error string
  // The info for all transactions this public key is associated with from oldest
  // to newest. If “IDsOnly” is set to true, each Transaction object will contain
  // only TransactionIDBase58Check. Otherwise, all other fields will be set as well.
  Transactions [
    Transaction {
      // Always set.
      TransactionIDBase58Check string
      // Rest of fields are as defined previously, but only set if
      // IDsOnly is unset or false.
      ...
  }, ... ]
```

### /api/v1/node-info

General information about the node’s blockchain and sync state can be queried using this endpoint.\
\
The blockchain does a “headers-first” sync, meaning it first downloads all DeSo headers and then downloads all blocks.\
\
This means that, when the node is first syncing, the tip of the best “header chain” may be ahead of of its most recently downloaded block.\
\
In addition to syncing DeSo headers and DeSo blocks, a DeSo node will also sync all of the latest Bitcoin headers to power its built-in decentralized Bitcoin <> DeSo swap mechanism.\
\
For this reason, the endpoint also returns information on the node’s best Bitcoin header chain, which is distinct from its DeSo chain.

```
PATH: /api/v1/node-info
METHOD: POST
RETURNS
  DeSoStatus {
    // A summary of what the node is currently doing.
    State string

    // We generally track the latest header we have and the latest block we have
    // separately since headers-first synchronization can cause the latest header
    // to diverge slightly from the latest block.
    LatestHeaderHeight     uint32
    LatestHeaderHash       string
    LatestHeaderTstampSecs uint32

    LatestBlockHeight     uint32
    LatestBlockHash       string
    LatestBlockTstampSecs uint32

    // This is non-zero unless the main header chain is fully current. It can be
    // an estimate in cases where we don't know exactly what the tstamp of the
    // current main chain is.
    HeadersRemaining uint32
    // This is non-zero unless the main header chain is fully current and all
    // the corresponding blocks have been downloaded.
    BlocksRemaining uint32
  }
  BitcoinStatus {
    // We download Bitcoin headers in order to power the decentralized
    // Bitcoin <> DeSo swap built-in to the app,
    // which allows users to convert Bitcoin into DeSo without needing
    // to trust third-parties.
    //
    // This part of the response has the same schema as DeSoStatus, only 
    // the block information won’t be populated since we only download
    // Bitcoin headers not full Bitcoin blocks.
  }
  DeSoOutboundPeers []PeerResponse {
    IP           string
    ProtocolPort uint16
    JSONPort     uint16
    IsSyncPeer   bool
  }
  DeSoInboundPeers []PeerResponse{
    // Same schema as above
  }
  DeSoUnconnectedPeers []PeerResponse{
    // Same schema as above
  }
  BitcoinSyncPeer []PeerResponse{
    // Same schema as above
  }
  BitcoinUnconnectedPeers []PeerResponse{
    // Same schema as above
  }
  // The public keys the node is currently sending block rewards to.
  // If no public keys have been specified then the node will not be mining.
  MinerPublicKeys []string
```

### /api/v1/block

A block’s information can be queried using either the block hash or height. To get all blocks in the chain, simply query this endpoint by enumerating the heights starting from zero and iterating up to the tip.\
\
The tip height and hash can be obtained using the `/node-info` endpoint.

```
PATH: /api/v1/block
METHOD: POST
POST PARAMS:
  // Block height. 0 corresponds to the genesis block. An error will be
  // returned if the height exceeds the tip. This field is ignored if HashHex is
  // set.
  Height int64
  // Hash of the block to return. Height is ignored if this is set.
  HashHex string
  // When set to false, only returns the header of the block requested
  // not the full block. Otherwise, returns the full block.
  FullBlock bool
RETURNS
  // Blank if successful. Otherwise, contains a description of the
  // error that occurred.
  Error string
  // The information contained in the block’s header.
  Header {
    // The hash of the block that was queried.
    BlockHashHex string
    // Generally set to zero
    Version uint32
    // Hash of the previous block in the chain.
    PrevBlockHashHex string
    // The merkle root of all the transactions contained within the block.
    TransactionMerkleRootHex string
    // The unix timestamp (in seconds) specifying when this block was
    // mined.
    TstampSecs uint32
    // The height of the block this header corresponds to.
    Height uint32
    // The nonce is encoded as a little-endian 32-bit integer. If more than 2^32
    // hashes are required in order to mine a block, the block reward's ExtraData
    // field can be twiddled to change the merkle root to give a miner a fresh set
    // of 2^32 header nonces to try. Note that we don't use 64 bits (or more) because
    // keeping the header small is important for the efficiency of light clients and
    // because it doesn't add much value over over just twiddling the ExtraData
    // every 2^32 values.
    Nonce uint32
  }
  // A list of Transactions, where the Transaction object is as defined previously.
  Transactions [
    Transaction {
    }, ... 
  ]
```


# Node: Setup

Description of steps required to download and start your node

Setting up a Deso Node is a simple process, but first verify that you have both [Broken mention](broken://pages/Shx5TPiPCTl9YBknbomU#docker) and [Broken mention](broken://pages/Shx5TPiPCTl9YBknbomU#git) installed.

### Cloning The Repository&#x20;

Create a folder where you want your node to be held then open your terminal of choice in that location.

Execute the command `git clone` [`https://github.com/deso-protocol/run.git`](https://github.com/deso-protocol/run.git) in your terminal.

![](/files/w8eogKWrkURCTXnhpMbo)

### Download The Containers

Once the installation is complete navigate to the run folder with `cd run` and execute the command `./run.sh`&#x20;

![](/files/okQDZEtIyyV4N2vytV0U)

A small terminal will appear and automatically download the containers for the node's frontend, backend, and nginx. This may take a few minutes.

Note in order to turn your node on or off open the Docker GUI navigate to the containers/apps tab, hover over the run tab, and hit the start/stop button to turn your node on or off.

![](/files/bHh7DTXvsjP6ljA8BtH6)

Congratulations, your Deso node is now running locally! Navigate to [http://deso.run](http://deso.run/) or `locahost:8080` in your browser to see your local instance.&#x20;


# Node: Staying Up-To-Date

This is a step-by-step guide on how to stay up to date with hardforks of the core repository, as well as instructions for core team members on how to execute updates that could cause a hard fork on the network.\
\
This doc should help node operators and the core team release new code in an organized way, particularly so that the developer community has sufficient time and resources to upgrade their nodes.

## Instructions for Node Operators <a href="#cv2t10tt14ya" id="cv2t10tt14ya"></a>

1. Subscribe to release notifications on GitHub
   * Which repos?
     * <https://github.com/deso-protocol/core> (important)
     * <https://github.com/deso-protocol/backend> (important)
     * <https://github.com/deso-protocol/rosetta-deso> (important for exchanges like Coinbase)
     * <https://github.com/deso-protocol/identity>
     * <https://github.com/deso-protocol/frontend>
   * How to subscribe
     1. Click “Watch” at the top
     2. Select “Custom”
     3. Check “Releases”<br>
2. Whenever a major version update occurs, e.g. moving from 2.9.9 to 3.0.0, be sure to read the release notes and reboot your node within the next week to avoid issues
   * Note that occasionally a resync will be required, which could cause \~20 minutes of downtime unless done in parallel with a second running node. Be sure to read the release instructions to avoid any interruptions.<br>
3. Follow [@deso](https://diamondapp.com/u/deso) and [@nader](https://diamondapp.com/u/nader) on [node.deso.org](https://node.deso.org/) or [DiamondApp](https://diamondapp.com/) for on-chain announcements and discussion<br>
4. Follow [@desoprotocol](https://twitter.com/desoprotocol) and [@nadertheory](https://twitter.com/nadertheory) on Twitter

## Instructions for Core Team <a href="#id-9wdvp7tesgvk" id="id-9wdvp7tesgvk"></a>

### Code preparation <a href="#id-2tidf3tg7ql4" id="id-2tidf3tg7ql4"></a>

1. Gate all the forking changes by a ForkHeight which initially should be set to `math.MaxUint32` for both mainnet and testnet, and 0 for regtest.<br>
2. Verify that the code passes all basic tests:
   1. core unit tests
   2. core integration tests
   3. node syncs with hypersync + txindex on testnet and mainnet
   4. node syncs with blocksync + txindex on testnet and mainnet
   5. rosetta can sync mainnet
   6. repeat steps c. and d. for postgres
   7. test that all of the changes work in the reference frontend
   8. make sure to run more comprehensive tests when deploying a complex change<br>
3. Assuming you’re ready with all the content for the steps in the next sections, you should announce everything at 12:00 PM PT and set the testnet fork height to 1 day from the announcement, and the mainnet fork height to **a minimum of** 7 days from the announcement.
   * We will strive to give as much time for node operators to upgrade as possible, erring on the side of two weeks.\
     \
     However, in the interest of moving quickly, it will sometimes be necessary to make updates with less warning, though generally with no less than one week of warning.

### Release preparation <a href="#nkce44tidl7s" id="nkce44tidl7s"></a>

1. Come up with a description of what happens in the fork. Make it a couple sentences, or a couple paragraphs depending on the scope of the change. See what fits based on next steps.<br>
2. Draft a Fork Preparation Checklist document which is a step-by-step checklist/walkthrough of what node operators need to do in order to upgrade their nodes (inspired by [prism’s merge preparation checklist](https://docs.prylabs.network/docs/prepare-for-merge))<br>
3. (Optionally) Write a before and after table which describes what happens in the fork. The left column should describe different aspects of the “before” tech and the right shows how they updated / changed “after” the fork. (also [prism’s merge preparation docs](https://docs.prylabs.network/docs/prepare-for-merge#the-merge-before-and-now))<br>
4. Put all of the above in a new draft release on github, similar to how [consensys does it with teku](https://github.com/ConsenSys/teku/releases), or how [ethereum does it](https://github.com/ethereum/go-ethereum/releases)<br>
5. Assuming the release number is XX.YY.ZZ (major.minor.patch):<br>
   * You should increment the major XX
     * -> if the node operators will be required to upgrade their software within a fixed amount of time, otherwise risking ending up on a stale fork.<br>
   * You should increment the minor YY
     * -> if the node operators can do nothing and still properly participate in the network. The code augments the node in a backwards-compatible fashion.<br>
   * You should increment the patch ZZ
     * -> If the update fixes a bug in a backwards-compatible fashion.<br>
6. Cut the new release

### Announcement <a href="#persa8n1a2dg" id="persa8n1a2dg"></a>

1. Create twitter announcement for the fork
2. Create diamond announcement for the fork
3. Create discord announcement for the fork


# Node: FAQ

Description of frequently asked questions on Deso nodes

## The Power of Decentralization

DeSo is unlike any existing social network in that the data is fully-decentralized and stored on a blockchain like Bitcoin. **This means that anyone on the internet can run a DeSo "node" and download a** ***full copy*** **of all the data, with real-time updates, without needing to ask for permission and without the risk of being de-platformed.**

## What Can You Do With a Node?

Running a node gives you full access to the DeSo firehose. Access to every profile, post, follow, creator coin trade, etc... But what can you do with all this power?

### **Running your own feed**

When you run a node, it starts with a blank global feed and an "Admin" panel that you can use to start adding posts to it. **All of the same tools that the diamondapp.com team uses to manage their global feed are now available to you to manage a feed of your own.**

Essentially, running a DeSo node allows you to expose your own "view" of the firehose of content. For example, [Diamond](https://diamondapp.com) node exposes all of the crypto-related content, but when you run your own node you have full control to surface whatever content speaks to you. What will you do with your feed? Here are some ideas for feeds that we think would be popular:

* **A feed for every country and every language.** Isn't it weird that people all over the world consume information curated predominantly by the US? How much does an engineer working in Silicon Valley really know about what people in other countries want to see, or what features they want? In the past, we were stuck with this model because US companies built a data network effect that entrenched them, even in non-US countries. But DeSo can break this status quo because all of its data is open and the barrier to entry to starting a competitive feed is virtually zero. For the first time, people who actually live in a country can curate a feed for their people, no matter how large or small their country is. And this applies to every country that succumbed too quickly to the network effects of the Silicon Valley tech companies. By lowering the barrier to entry to creating a feed, and opening up the data firehose to anyone, we think DeSo has the potential to bring international social media products to a whole new level.
* **The politics-focused feed.** Imagine a feed where all the posts from the top political figures are highlighted. You could even imagine segmenting the firehose into two feeds: a "red" feed and a "blue" feed that's dedicated to each political party.
* **The sports-focused feed.** Wouldn't it make sense for someone to operate a feed that just highlights all of the best sports content from the best sports influencers? So many people are interested in this content, and we think it deserves its own feed.
* **The NSFW feed.** There are so many talented adult influencers on DeSo, with thousands of followers, who are posting every day. It's about time they had their own feed dedicated to them.

We're just scratching the surface here-- it's now up to you, the community, to figure out how best to display the DeSo firehose. Reddit pioneered the concept of a "Subreddit," but the problem with a Subreddit is that every time one is created, it has to solve a "chicken and egg" problem with regard to its content. If nobody is posting, then the subreddit has no content-- but without content, nobody will start posting. DeSo bascially takes the subreddit concept to the next level by solving the "content" part of the equation for everyone. When you run a node, you don't need to bootstrap content because you have full access to the DeSo firehose. All you need to do is curate it in some interesting way and you'll have created value for anyone who visits your node.

### Add social to your platform

Suppose you're a platform with millions of users like Coinbase or Robinhood, or even traditional media companies like ESPN. Your users would probably love it if you could integrate a social component into your products-- but you can't because Twitter and Facebook don't allow it. They [closed down their APIs](https://www.theverge.com/2018/8/16/17699626/twitter-third-party-apps-streaming-api-deprecation) a long time ago because they realized that third-party integrations eat into their ad revenue. Every user who engages on a third-party platform is a user who's engaging less on Twitter and Facebook.

Enter DeSo. With DeSo, you don't need to build a billion-user data moat in order to be able to add social features to your platform. All you need to do is run a DeSo node, and use its API to expose whatever content you want. Suddenly, with just one engineer's worth of effort, any major platform can spin up a social product that's adjacent to its core business. Moreover, it's possible that the best feeds will come from existing publishers that have already built a competency in a particular area. For example, ESPN might be the best entity to run the sports-focused feed because of their relationships and connections, and now they can.

### Analysis tools

Building the best analysis tools requires access to the best data, and running a node is the best way to get full access to the DeSo firehose. Until now, the DeSO nodes have had to set up rate limits to avoid having our machines get overloaded. But now, because DeSo is a blockchain that allows anyone to run a full copy of the platform, anyone who wants to build analytics tools can simply run a node and query it in whatever way they want.

### Invent your own features

When you run a node, you have the flexibility to expose the DeSo content in whatever way most resonates with your users. If you wanted to, you could even build a whole new frontend with totally different features than what the "default" node gives you. If you feel like DeSo is missing a feature, like dark mode or paid messages or better filtering for spam for example, now you can build it and run your own node to back it.

## Making Money on Your Node

Incentives are key to making DeSo truly decentralized in the long run. It's not sufficient that nodes be runnable by the community, they must be *profitable* to run as well. Many cryptocurrencies struggle with this, and even Bitcoin and Ethereum nodes are still largely run by volunteers. DeSo is truly unique in this regard, however, because the social features it introduces give node operators incentives that other blockchains don't have.

The above being said, there are several ways that DeSo node operators can earn a profit:

* **Promoted content.** Because running a node comes with the ability to have a social media product with minimal marginal effort, every node operator has an opportunity to amass and monetize the reach that comes from curating a popular feed. This can be as simple as showing promoted posts that partners pay the node operator to pin to their feed.
* **Trading fees.** Anyone who runs a node can modify their frontend to add trading fees on every creator coin trade, which go to the node operator's wallet. By doing this, any node operator basically doubles as a crypto exchange.
* **Other transaction fees.** Any transaction users complete on one's node can be augmented to contain a small fee that goes to the node operator. Thus there should eventually arise an efficient market for node operator fees that is high enough to justify operating a node.

The above mechanisms don't even factor in profits that could be derived from augmenting the DeSo feature set. For example, if someone creates an app experience for DeSo that is significantly better than alternatives, they could even charge a monthly subscription fee or some other premium to cover costs.

## How to Run a Node

Running a node currently requires a modest amount of technical know-how. For the full instructions on how to run a node, checkout this [Node: Setup](/deso-nodes/setup) guide.

Once a node is running, it syncs all of the blocks from its peers, as well as the transactions in the "mempool," which have yet to be mined into a block. Every node comes with an Admin panel with a Network tab that allows you to monitor the node's sync state.

![](/files/-Mk552kFqcsclpOGgUqr)

Once your node is synced, you have access to the full firehose of DeSo data in real time! Below are some tips on how take full advantage of your node.

* Go to your Admin tab and watch the unfiltered feed update as your node syncs. It's like a time machine!
* Try to whitelist some posts in the Admin tab and see that they've made their way onto your global feed.
* Read through the flags available in the [dev.env](https://github.com/deso-protocol/run/blob/main/dev.env) file. You can adjust these flags however you want, but note that we strongly recommend keeping your node in read-only mode for now. Turning read-only mode off could cause users who visit your node to make transactions that are not ultimately confirmed.
* Set `ADMIN_PUBLIC_KEYS` to your public key so that the Admin tab is only visible to your username.
* Set `SUPER_ADMIN_PUBLIC_KEYS` to your public key so that the Super Admin tab is only visible to your username.
* Whitelist some posts and verify that they show up on the global feed.
* Deploy your node on any cloud provider with a static IP to make it accessible to anyone on the internet.
* Set a `PASSWORDS_FILE` if you want to restrict read access to your node.
* Add an `SSL_CERT_DIR` and `SSL_DOMAIN` using a letsencrypt cert in order to protect your node with HTTPS.
* Set the `TWILIO*` flags to allow new users to get some starter DeSo.
* Set a `SUPPORT_EMAIL` so your users can contact you if they run into trouble.
* Play with the logging verbosity by increasing `GLOG_V`.

## Managing Your Feed

To manage your feed, start by navigating to the Admin tab as shown below. The Admin tab shows the full firehose of posts in real time, with a button next to each one that allows you to add it to the global feed. You can also sort the posts by DESO. These are all the same tools that the bitclout.com mods have, now at your fingertips through the power of decentralization.

![](/files/-Mk6-1vIjAZU__FSX_r3)

You can also add any post from anyone's profile to the global feed simply by hitting the dropdown at the top-right of the post. You can also pin posts to your feed, which is a good way of communicating announcements to your user-base.

![](/files/-Mk5t9kZGi1Wgtn8Pu2z)

When you run a node, you act as a moderator and have a variety of superpowers that help you manage spam and harmful content.

* **Blacklisting** a profile removes it everywhere except from peoples' wallet pages. This makes it so that anyone who was holding the blacklisted profile can sell out of their holdings.
* **Graylisting** a profile removes it from the leaderboard, removes it from search, removes its comments from threads, and removes its posts from the Admin panel.
* **Whitelisting** a profile makes that user's posts show up on the global feed automatically with some frequency (currently it allows five posts per day).
* Finally, a mod can allow a phone number to be re-used to claim starter DeSo. This is useful for various testing situations.

![](/files/-Mk54dJ9rOIY_pVr7Tb6)

When you've set your public key as an `ADMIN_PUBLIC_KEY`, the Admin tab becomes visible only to you. This is a critical step in securing your node. Not doing this would make it so that all your users can add posts to the global feed.

## Super Admin Public Keys

Within the Admin Panel, there is a `Super` tab which is only accessible by Super Admins. Super Admin can manage user verification and $DESO purchasing behavior from the `Super` tab.

### Username Verification

![](/files/-Mk54hKOL1-Yp0hB6lLh)

Super Admins can grant verification badges (on their node) to a user by putting the username in the `Grant Verification Badge` input box and then clicking `Verify`. Similarly, a Super Admin can revoke verification by putting the username in the `Remove Verification Badge` and then clicking `Remove`.

### Buy $DESO Management

Any node can sell $DESO if they set the following flags appropriately. Super Admins can set two values in the `Super` tab to manage the price at which $DESO is sold on their node: `USD-to-DeSo Reserve Price`and `Buy DeSo Fee Rate`.

![](/files/-Mk54lwGk9RXmfcVQ41R)

#### USD-to-DeSo Reserve Price

This is the minimum price at which you are willing to sell $DESO on your node. If the price retrieved from exchange APIs is lower than this amount, your node will sell $DESO at this reserve price instead of the API price. Additionally, the price in the right sidebar will appear the reserve price in the event that the price from the API dips below the reserve price.

#### Buy DeSo Fee Rate

This is a percentage-based fee applied to all $DESO purchased on your node. If the current price of $DESO in USD is $100 and the `Buy DeSo Fee Rate` is 5%, the buyer will pay $105 per $DESO and the node operator has earned $5 net. For more details on configuring your node to sell $DESO, please read the section titled `Sell $DESO on your node`.

## Sell $DESO on your node

To simplify the on-boarding experience for new users on your node, you can sell $DESO for Bitcoin directly to users. To configure your node to sell $DESO, please set the following flags:

* `BUY_DESO_SEED`: This is a seed phrase for the public key that contains $DESO that you will sell to users. As with all seed phrases, keep this secret and share it with nobody. Take extra precautions to not commit it to version control and quickly move funds if this seed is ever compromised.
  * You will need to deposit $DESO to the public key for this seed phrase. All $DESO purchases on your node will send $DESO from this wallet.
* `BUY_DESO_BTC_ADDRESS`: This is a Bitcoin address you control. When users purchased $DESO with Bitcoin, the Bitcoin will arrive at this address.

## How Users Login

When a user logs in on your node, they have the ability to sign in with their DeSo identity, without having to re-enter their seed phrase. Once a user signs in, your node can sign transactions on their behalf with varying levels of approval required depending on what kind of permission the user granted. This creates a login mechanism for node operators that is as easy for users as "login with Facebook," but it unlocks a wallet in addition to a user's identity.

## FAQ

Answers to common questions and issues about running your own node:

### What are the minimum requirements for syncing a node?

We recommend having a machine with at least 32GB of RAM and 350GB of storage (as at 21 July 2021). If TXIndex is disabled, then you need about 200GB in total. The Blockchain DB takes up about 90 GB, and the TXIndex takes up 160 GB. THe DB+TXindex size grows by about 50GB a month currently.

### How do I configure SSL?

There is an example SSL configuration in `nginx.dev`.

### How do I use the BlockCypher API?

BlockCypher will help prevent double-spends in the mempool. You can signup for a [BlockCypher](https://www.blockcypher.com/) account on the BlockCypher website. BlockCypher does offer a free amount of API calls.

Once you have signed up for an account you may copy a token from the [tokens](https://accounts.blockcypher.com/tokens) section of the dashboard.

You will copy this token in your `dev.env` file as the value for `BLOCK_CYPHER_API_KEY`.

### What type of records do I use with custom domains?

You must create two seperate **A** type domain records.

Both records should point to the IP address of your node.

#### Example DNS Records:

| Hostname          | Type | TTL | Priority | Content     |
| ----------------- | ---- | --- | -------- | ----------- |
| node.`DOMAIN`.com | A    | 299 |          | `IPADDRESS` |
| api.`DOMAIN`.com  | A    | 299 |          | `IPADDRESS` |

If you do not create both records you will be unable to use a custom domain.

### Can my node write back to the mainnet?

Yes! Every transaction is broadcast to all other nodes on the network, and should eventually be mined into a block.

### What does Twilio provide to my node?

Twilio provides an SMS API that allows you to confirm user phone numbers and thus send them currency from your seed wallet set inside the `dev.env` file. If you do not have this set users will be unable to verify a phone number.

Twilio pricing can be reviewed [here](https://www.twilio.com/sms/pricing/us).


# Run a Validator

Instructions on how to stake/unstake $DESO and run a validator

## Getting Help from the Community <a href="#h.7vr9ab79ocun" id="h.7vr9ab79ocun"></a>

If you get stuck at any point, [go here for help](/openfund/the-deso-python-sdk/getting-help-from-the-community).

## Video Walkthroughs <a href="#h.7vr9ab79ocun" id="h.7vr9ab79ocun"></a>

* [An Overview of DeSo](https://www.google.com/url?q=https://www.youtube.com/watch?v%3DKXBTlSryNwA\&sa=D\&source=editors\&ust=1720503194993230\&usg=AOvVaw1P4wF7ok3tOeGmN-FKLMRZ)
* [Staking and Unstaking $DESO](https://www.google.com/url?q=https://www.youtube.com/watch?v%3DViIJ6VMRENo%26feature%3Dyoutu.be\&sa=D\&source=editors\&ust=1720503194993554\&usg=AOvVaw3SVx-lR6a6m0H3uP22DrRP)
  * For Mainnet, use [explorer.deso.com/validators](https://www.google.com/url?q=https://explorer.deso.com/validators\&sa=D\&source=editors\&ust=1720503194993782\&usg=AOvVaw3NjwImbq8S6SWdBCkxmD29)
  * For Testnet, use [explorer-testnet.deso.com/validators](https://www.google.com/url?q=https://explorer-testnet.deso.com/validators\&sa=D\&source=editors\&ust=1720503194993913\&usg=AOvVaw3RckY4HfuGm_FICSfw79DX)
* [Running a Node and Validator](https://www.google.com/url?q=https://www.loom.com/share/8ea0dc18fe204678b2665fecbafbf874?sid%3D37ab0e0e-ec1c-4530-bda4-c8b314298dbf\&sa=D\&source=editors\&ust=1720503194994260\&usg=AOvVaw3SnpLWshcbt-2HFkSBGDAA)
  * IMPORTANT: [See updates and extra notes here](https://www.google.com/url?q=https://docs.google.com/document/d/1q39rKRgua-rLSCbq842elIu_V7siRn-2aMn_c3IG3ag/edit\&sa=D\&source=editors\&ust=1720503194994542\&usg=AOvVaw1Vb6ief8J7S9Aqfi8VjJBv)

## Getting Started <a href="#h.vaab5azenvay" id="h.vaab5azenvay"></a>

* **Background:**
  * [What is DeSo?](https://www.google.com/url?q=https://deso.com\&sa=D\&source=editors\&ust=1720503194994945\&usg=AOvVaw1S11-Ld78F-rvbliLTG7l_)
  * [Our vision](https://www.google.com/url?q=https://docs.deso.org/\&sa=D\&source=editors\&ust=1720503194995143\&usg=AOvVaw1cogkeRRdSE96QMD5Vx9Ti)
  * [Current roadmap](https://www.google.com/url?q=https://docs.deso.org/deso-roadmap\&sa=D\&source=editors\&ust=1720503194995361\&usg=AOvVaw3fK3gPElyr-nNiQb27o9eB)
  * [Focus](https://www.google.com/url?q=https://focus.xyz\&sa=D\&source=editors\&ust=1720503194995538\&usg=AOvVaw27wq2Q6CzCsenzeloRCszV) (Coming Soon!)
  * [What is Revolution Proof of Stake?](https://www.google.com/url?q=https://revolution.deso.com/\&sa=D\&source=editors\&ust=1720503194995749\&usg=AOvVaw0usuSgK_Mmq3Tswwa2Y0hm)
    * 1 second confirmation times
    * 500 posts per second (\~10% of Twitter Scale)
    * 20% APY
    * No slashing
    * Quick-unstaking
    * Burn-maximizing fees
    * Fully permission-less and decentralized
  * [Resources](https://docs.google.com/document/u/1/d/e/2PACX-1vTBJidczUhRBhl2hTo_75o8md0RNwFguF_FeUEG_CkooN5dMLBrGyqcXvIu5efE9iAhC8ZqRr_S89Ml/pub#h.gcb427f1q4hl)
* **Staking:**
  * [Staking Your $DESO](https://docs.google.com/document/u/1/d/e/2PACX-1vTBJidczUhRBhl2hTo_75o8md0RNwFguF_FeUEG_CkooN5dMLBrGyqcXvIu5efE9iAhC8ZqRr_S89Ml/pub#h.1owmq1kzue21)
  * [Unstaking your $DESO](https://docs.google.com/document/u/1/d/e/2PACX-1vTBJidczUhRBhl2hTo_75o8md0RNwFguF_FeUEG_CkooN5dMLBrGyqcXvIu5efE9iAhC8ZqRr_S89Ml/pub#h.qe2fcaayxtb)
* **Running a Node & Validator**
  * [Running a Node](https://docs.google.com/document/u/1/d/e/2PACX-1vTBJidczUhRBhl2hTo_75o8md0RNwFguF_FeUEG_CkooN5dMLBrGyqcXvIu5efE9iAhC8ZqRr_S89Ml/pub#h.85kweyti5tlv)
  * [Running a Validator](https://docs.google.com/document/u/1/d/e/2PACX-1vTBJidczUhRBhl2hTo_75o8md0RNwFguF_FeUEG_CkooN5dMLBrGyqcXvIu5efE9iAhC8ZqRr_S89Ml/pub#h.79y85q98fhdi)

## Resources <a href="#h.gcb427f1q4hl" id="h.gcb427f1q4hl"></a>

* [deso.com](https://www.google.com/url?q=https://deso.com\&sa=D\&source=editors\&ust=1720503194997379\&usg=AOvVaw1uZW3409CJ-nz6rFVhxwbR)
  * [Current roadmap](https://www.google.com/url?q=https://docs.deso.org/deso-roadmap\&sa=D\&source=editors\&ust=1720503194997648\&usg=AOvVaw0vfOQaORDWyeCq4IhN3lsD)
* Block explorers:
  * [Mainnet block explorer](https://www.google.com/url?q=https://explorer.deso.com\&sa=D\&source=editors\&ust=1720503194997989\&usg=AOvVaw2699kku36pIIMimwLb8-22) ([legacy explorer](https://www.google.com/url?q=https://explorer.deso.org/\&sa=D\&source=editors\&ust=1720503194998169\&usg=AOvVaw0FPzzgSwCrk3_HUiXJOsqn))
  * [Testnet block explorer](https://www.google.com/url?q=https://explorer-testnet.deso.com/\&sa=D\&source=editors\&ust=1720503194998461\&usg=AOvVaw1f-uKZOUvFstxKffCWOmOF) ([legacy explorer](https://www.google.com/url?q=https://explorer.deso.org/?query-node%3Dhttps:%252F%252Ftest.deso.org\&sa=D\&source=editors\&ust=1720503194998659\&usg=AOvVaw06EyOPcKqQmiiullVuswEi))
  * Note: The legacy explorer is more accurate, but much less readable. If you run into an issue with the main explorer, always check back with the legacy explorer for now.
* Validator Hubs:
  * [Mainnet validator hub](https://www.google.com/url?q=https://explorer.deso.com/validators\&sa=D\&source=editors\&ust=1720503194998986\&usg=AOvVaw1ACqGhRtFJnXyNCYwuPgnh)
  * [Testnet validator hub](https://www.google.com/url?q=https://explorer-testnet.deso.com/validators\&sa=D\&source=editors\&ust=1720503194999178\&usg=AOvVaw02R496bT7UWEKd3cTdIJUs)
* Managing funds, managing identity, and generating transactions:
  * [The DeSo Wallet](https://www.google.com/url?q=https://wallet.deso.com/\&sa=D\&source=editors\&ust=1720503194999399\&usg=AOvVaw2_F7oQ72XplTE0KPys7AYJ) (and the [Testnet DeSo Wallet](https://www.google.com/url?q=https://wallet-testnet.deso.com/\&sa=D\&source=editors\&ust=1720503194999536\&usg=AOvVaw2piTIS4QALfp7KGdcRdsRf))
    * You can manage your funds here, or using the reference nodes listed below, or using any app built on DeSo, including [Diamond](https://www.google.com/url?q=https://diamondapp.com\&sa=D\&source=editors\&ust=1720503194999750\&usg=AOvVaw2b8d0uW_3qIhSFlxoUWu8T), [Openfund](https://www.google.com/url?q=https://openfund.com\&sa=D\&source=editors\&ust=1720503194999899\&usg=AOvVaw0co2vPjWq_2n3tALkDbaJC), and [Focus](https://www.google.com/url?q=https://focus.xyz\&sa=D\&source=editors\&ust=1720503195000027\&usg=AOvVaw2F3cQyL6bGz-qQz5qi3nmc) (Coming Soon!).
    * Every DeSo app, including the wallet, has access to the same blockchain data, so it doesn’t matter which app you use to manage your account.
    * Technically, your DeSo public/private keys are managed locally in your browser by the [DeSo Identity iFrame](https://www.google.com/url?q=https://docs.deso.org/deso-blockchain/privacy-and-security%23do-deso-applications-have-access-to-my-seed-phrase\&sa=D\&source=editors\&ust=1720503195000458\&usg=AOvVaw2KfbM7tqlz-hJ8umjFu3ym), which allows you to sign transactions on any app on the web (with approval). It’s exactly like MetaMask, only it doesn’t require you to install a browser extension, and it can do much more than send/receive funds.
* [Mainnet Reference Node](https://www.google.com/url?q=https://node.deso.org/\&sa=D\&source=editors\&ust=1720503195000648\&usg=AOvVaw2xhUMmM4tvxbw2bWvtJk2X) (and the [Testnet Reference Node](https://www.google.com/url?q=https://test.deso.org/\&sa=D\&source=editors\&ust=1720503195000808\&usg=AOvVaw3cotlIKlW94MhnQ-Kbzk22))
  * The reference nodes can generate the full set of DeSo transactions, including making posts, following users, etc…, which the wallet app may not be able to do. You can also try other nodes like [Diamond](https://www.google.com/url?q=https://diamondapp.com\&sa=D\&source=editors\&ust=1720503195001030\&usg=AOvVaw1UehhmztpzEFtLOHG9GdHo), [Openfund](https://www.google.com/url?q=https://openfund.com\&sa=D\&source=editors\&ust=1720503195001185\&usg=AOvVaw34u7yHwLqz4vjzTf4dCMAI), or [Focus](https://www.google.com/url?q=https://focus.xyz\&sa=D\&source=editors\&ust=1720503195001346\&usg=AOvVaw2_AHi047e4-7L_SDkY5RmG) (Coming Soon!)
  * Enter your phone number on the testnet node to get 1 testnet $DESO to test your apps with
* Other recommended nodes:
  * [Diamond](https://www.google.com/url?q=https://diamondapp.com\&sa=D\&source=editors\&ust=1720503195001689\&usg=AOvVaw0DsTUjcEwdlN0UBlNGvpHD), [DeSocialWorld](https://www.google.com/url?q=https://desocialworld.com\&sa=D\&source=editors\&ust=1720503195001817\&usg=AOvVaw00612Z7xHE364tngOeFZp5), [Openfund](https://www.google.com/url?q=https://openfund.com\&sa=D\&source=editors\&ust=1720503195001959\&usg=AOvVaw2_FAO78YT90U9aY8zhtsrq), [Focus](https://www.google.com/url?q=https://focus.xyz\&sa=D\&source=editors\&ust=1720503195002111\&usg=AOvVaw0qv9xNHoEHf-1tljAOlPCV) (Coming Soon!)
  * You can also run your own node locally on your own computer!
* [The DeSo Docs](https://www.google.com/url?q=https://docs.deso.org/\&sa=D\&source=editors\&ust=1720503195002352\&usg=AOvVaw33W_2S0LlUSSzVwwWFf5ck)
  * Use CTRL+K to find documentation on any transaction type, or any other information you may need.
  * These docs will be refreshed after the launch of Revolution PoS on mainnet so note that some things may be out of date!
  * Good starting points:
    * [Current Roadmap](https://www.google.com/url?q=https://docs.deso.org/deso-roadmap\&sa=D\&source=editors\&ust=1720503195002740\&usg=AOvVaw0NGrUqGCR9vEjJXfN-UyrQ)
    * [List of Notable DeSo Apps](https://www.google.com/url?q=https://docs.deso.org/deso-applications\&sa=D\&source=editors\&ust=1720503195002931\&usg=AOvVaw20C2NX8OczFmw28a3uWWA2)
    * [Building a DeSo App](https://www.google.com/url?q=https://docs.deso.org/deso-tutorial-build-apps\&sa=D\&source=editors\&ust=1720503195003131\&usg=AOvVaw1rsbzfbl_Wzxg9rMG4JtsQ) (Getting Started)
    * [Architecture Overview](https://www.google.com/url?q=https://docs.deso.org/deso-repos/architecture-overview\&sa=D\&source=editors\&ust=1720503195003304\&usg=AOvVaw3E1LJx8t-3VpqyN7KlRhu-)
* [Exchange listing API](https://www.google.com/url?q=https://docs.deso.org/deso-exchange-listings/exchange-listing-api\&sa=D\&source=editors\&ust=1720503195003573\&usg=AOvVaw2ndD5F9vsFNHmG_lZl12NA)
  * $DESO is currently listed on [Coinbase](https://www.google.com/url?q=https://www.coinbase.com/advanced-trade/spot/DESO-USD\&sa=D\&source=editors\&ust=1720503195003820\&usg=AOvVaw3YhNSw3s54rBVUdd2sPKvU), [Gate](https://www.google.com/url?q=https://www.gate.io/trade/DESO_USDT?ref%3D3018394\&sa=D\&source=editors\&ust=1720503195003953\&usg=AOvVaw1-q9UFr73NIEpC6OEvPcdb), and [Huobi](https://www.google.com/url?q=https://www.htx.com/trade/deso_usdt?invite_code%3Dd8c53\&sa=D\&source=editors\&ust=1720503195004082\&usg=AOvVaw0RsBe-OA7PUq0fg4oG2NEq).
  * It can also be traded permissionlessly via the DeSo DEX on [Openfund](https://www.google.com/url?q=https://openfund.com/trade/deso\&sa=D\&source=editors\&ust=1720503195004269\&usg=AOvVaw08zhRM-XX39fmRl-km-dR8) or [HeroSwap](https://www.google.com/url?q=https://heroswap.com\&sa=D\&source=editors\&ust=1720503195004376\&usg=AOvVaw3UfkK1iWSFc7as6Wx5rJdl).
  * $DESO can be listed on any exchange permissionlessly using this guide.
* [About Revolution Proof of Stake](https://www.google.com/url?q=https://revolution.deso.com/\&sa=D\&source=editors\&ust=1720503195004589\&usg=AOvVaw0TkH21kS1nNpQEVaHg8l1W)

## Staking Your $DESO <a href="#h.1owmq1kzue21" id="h.1owmq1kzue21"></a>

Some info about staking with [Revolution Proof of Stake](https://www.google.com/url?q=https://revolution.deso.com/\&sa=D\&source=editors\&ust=1720503195004909\&usg=AOvVaw3QnhXsoI9Mbm1MvaZ2ZsUK):

* **20% APY to start.** The APY for staking your $DESO starts at 20% and adjusts depending on how much $DESO is staked on the network. You can always see an updated APY on the validators page on the block explorer ([mainnet](https://www.google.com/url?q=https://explorer.deso.com/validators\&sa=D\&source=editors\&ust=1720503195005157\&usg=AOvVaw3fx1mPHEsO3JaSZVXFUfX_), [testnet](https://www.google.com/url?q=https://explorer-testnet.deso.com/validators\&sa=D\&source=editors\&ust=1720503195005305\&usg=AOvVaw32ykBeqMktKaxRhxWq2xgi))<br>
* Revolution Proof of Stake makes a lot of improvements over state-of-the-art PoS systems, including Cosmos, Solana, and Ethereum. Some benefits of staking with Revolution are listed below:
  * **No slashing.** Revolution does not require slashing of stake. Instead, validators who are unresponsive are automatically “jailed” for a period of time, preventing them from harming consensus until they have resolved their issues. The only risk of staking to a bad validator is that you will miss out on rewards if they have downtime.<br>
  * **Quick unlocks.** Unlocking one’s stake takes only two hours, compared to weeks to months with \
    other protocols. And this amount will be decreased even further in the future.<br>
  * **Fully permissionless and decentralized.** Revolution is permissionless and does not require a minimum amount of stake to become a validator. The idea was to reproduce the level of permission-lessness of Proof of Work systems, but in a Proof of Stake context.<br>
* Learn more about Revolution and its many other breakthroughs by reading [the docs here](https://www.google.com/url?q=https://revolution.deso.com/\&sa=D\&source=editors\&ust=1720503195005829\&usg=AOvVaw3X_o7xnjNGHJtEXmxd3HF7).

**Staking your $DESO:**

* For Testnet only:
  * Pick up some free testnet $DESO
    * Visit [https://test.deso.org](https://www.google.com/url?q=https://test.deso.org\&sa=D\&source=editors\&ust=1720503195006186\&usg=AOvVaw0X21zHELERJPi6CM_ykFgN)
    * Create an account
    * When creating an account you can enter your phone number to get 1 free testnet $DESO from the faucet
    * Note that testnet $DESO does not have any value outside of the test environment!<br>
* Now that you have $DESO, head to the block explorer
  * [Testnet link](https://www.google.com/url?q=https://explorer-testnet.deso.com/\&sa=D\&source=editors\&ust=1720503195006535\&usg=AOvVaw1myxrpTi86UHU5d9hPL3EK)
  * [Mainnet link](https://www.google.com/url?q=https://explorer.deso.com/\&sa=D\&source=editors\&ust=1720503195006696\&usg=AOvVaw2FjShc1dnSm9CzgrPwGPpc)<br>
* Login to the block explorer by hitting “Login” in the top-right and selecting the account that holds your $DESO<br>
* After logging in, select Validators > Stats from the top menu
  * Note the APY at the top. This amount will change depending on how many people are staking<br>
* Choose a validator to stake to and click on their username
  * Note that you can sort validators by their Commission percentage, the number of stakers, and their total staked<br>
* Once on the validator’s page, click “Stake” and fill in the amount you want to stake<br>
* That’s it!

## Unstaking your $DESO <a href="#h.qe2fcaayxtb" id="h.qe2fcaayxtb"></a>

* Go back to the main validator page on the block explorer
  * [Testnet link](https://www.google.com/url?q=https://explorer-testnet.deso.com/validators\&sa=D\&source=editors\&ust=1720503195007487\&usg=AOvVaw3lTZ_tdrqDn8LNuTMsAv4U)
  * [Mainnet link](https://www.google.com/url?q=https://explorer.deso.com/validators\&sa=D\&source=editors\&ust=1720503195007662\&usg=AOvVaw03wk4x_yQYHDH80B2vD3Ok)
* Make sure you are logged in with the account that originally staked the $DESO
* Click “Unstake” on the /validators page

  <figure><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXcEkkwvj0js0ELMCvTp13orX8ZZqBH7umCP1w1pjinaONdjMnu1ig0QmBJK4U2ZCpCtpR-tdGNN1q3smS_M0g2buiyEeMPqagBjVW_z9LlzGxyBfzSJhnQhr8fC0jeIUwXhr6ikFzOk9zPBqujSFa-4TzQj?key=Oj9nXlPuOUnCJ5YUj2muHA" alt=""><figcaption></figcaption></figure>
* Select the amount of stake you want to remove
* Hit “Update Stake”
* After you unstake, your stake appears as a “Locked Stake Entry” and is locked for a 3 hour cooldown period. This prevents anyone from gaming the leader selection algorithm. You can see how much time is left before you can unlock by clicking “View Details.”

  <figure><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXczF-QtB1mfiTZu13WzWG4kZYGAZOAtcyfwWLH3-fE0zQnQjFT9phghuRP672HrkwdWZlv-dBPrScHTwB7leyfoRiVZz9E3sktSMcNXmTy1DIjz0S5U3bT1cyhsIuBt0W_PcgIwbVL6Q7tpsWqo5RHUq1lk?key=Oj9nXlPuOUnCJ5YUj2muHA" alt=""><figcaption></figcaption></figure>

  * Note that other protocols require weeks or months of cooldown, but Revolution PoS only requires three hours, and we aim to decrease this even further over time.
* After the cooldown period is over, you just hit “Unlock” on the locked stake entry to get your $DESO

## Running a Node <a href="#h.85kweyti5tlv" id="h.85kweyti5tlv"></a>

A **node** on the DeSo network is any machine that has a full copy of the blockchain, and that other nodes can sync from. When you run a node, you start by syncing data from other nodes on the network until you have a full copy of the network’s “state.” Once you’re up-to-date, you stay online and get new blocks as they’re proposed. Note that you don’t need to participate in consensus in order to run a node. You just need to stay up to date by downloading all the new blocks as they’re proposed.

A **validator** is a node that participates in consensus. With Revolution, validators vote on each new block that is proposed and propose blocks when it’s their turn to be “leader.” Being a validator means that you take on the responsibility of validating blocks but it also means you can earn a commission from anyone who stakes to you.

### Minimum Requirements <a href="#h.8qhon4v4xa14" id="h.8qhon4v4xa14"></a>

* Mainnet
  * Minimum:
    * RAM: 32GB
    * CPU: 4 cores (less may be OK)
    * Disk: 200GB
    * Notes
      * If you are running the minimum configuration, you must use --sync-type=blocksync. This is because using --sync-type=hypersync or --sync-type=hypersync-archival will cause you to exceed your RAM requirements
  * Recommended:
    * RAM: 64GB - 256GB
      * 128GB will be the safest bet, and will allow you to run with --sync-type=hypersync and --sync-type=hypersync-archival, which will sync your node much faster. However, if you’re building a machine from scratch to be a validator, we’d recommend you make it upgrade-able to 256GB in case we decide to increase requirements in the future. We have a recommended build below that achieves this.
    * CPU: 8 cores (less may be OK)
    * Disk: 500GB (less may be OK)
    * Recommended build (premium):
      * [24-core/48-thread, 256GB RAM, 4TB NVME ssd](https://www.google.com/url?q=https://newegg.io/cb6a734d\&sa=D\&source=editors\&ust=1720503195009580\&usg=AOvVaw0lUHJo9eB3M4QW_cHBPUsg)
      * You will also need [this Enermax cooler for your CPU](https://www.google.com/url?q=https://www.amazon.com/gp/product/B07H778NCW/ref%3Dppx_yo_dt_b_search_asin_title?ie%3DUTF8%26th%3D1\&sa=D\&source=editors\&ust=1720503195009807\&usg=AOvVaw004aurDIXheyaUskDRpd0n)
      * If you want, you can order less RAM to make the build a bit cheaper. The CPU is tough to downsize, though, because there aren’t many that support 8 RAM slots, which is \
        what we want everyone to have for future-proofing.<br>
* Testnet
  * Minimum and recommended:
    * RAM: 32gb
    * CPU: 2 cores
    * Disk: 50gb
  * Notes
    * Testnet currently requires --sync-type=blocksync, but this should be fixed soon.<br>
* Validator Requirements
  * In order to be a validator, your node must have a static IP and, ideally, a human-readable domain attached to that IP. We walk through setting that up in the video tutorial.

### Node Setup (Using Docker) <a href="#h.qddg2lmsopoz" id="h.qddg2lmsopoz"></a>

* **Get a machine.** First, you need to provision a machine with the minimum requirements. We walk through that in the video tutorial.
  * We recommend you run your machine from your house for maximum decentralization (and fun!). But provisioning a node on AWS or Google Cloud works great too.
  * Whatever you do, we recommend you run Ubuntu to minimize issues, but note that many members of the core team run nodes on Mac OS.
  * We have not tested thoroughly on Windows, but it should work. And if you run into issues you can always run your node from an Ubuntu virtual machine on Windows, e.g. using VirtualBox.<br>
* **Clone the run repo.** [The “run” repo here](https://www.google.com/url?q=https://github.com/deso-protocol/run\&sa=D\&source=editors\&ust=1720503195010995\&usg=AOvVaw0wJo4Lf4HIQ5DkMCJp3sFU) contains everything you need to get a node running with, a frontend interface attached. Some notes on using the run repo:
  * Start by cloning the run repo onto your node.
  * This branch has several docker-compose files. Let’s take a look at [testnet.docker-compose.yml](https://www.google.com/url?q=https://github.com/deso-protocol/run/blob/feature/proof-of-stake/testnet.docker-compose.yml\&sa=D\&source=editors\&ust=1720503195011260\&usg=AOvVaw36N3A5nxKRFD6YXwreYVrl):
    * It sets up a service named backend. This is the service that will connect to the rest of the network and sync data from it.\
      \
      The backend service has two ports: a “protocol” port `18000`, where other nodes connect to it, and an “API” port `18001`, which exposes a bunch of convenience endpoints and powers the frontend.<br>
    * It also sets up a service called “frontend” and “nginx” service. This allows you to visually manipulate your node.<br>
* **Run your node!** To run your node, all you have to do is type “`make testnet`” (if you have a permission error, use “`sudo make testnet`”). This will automatically run the testnet.docker-compose.yml and set up the backend+frontend+nginx services.
  * If you run into issues or you want to start “from scratch”, the Makefile also defines a command called “`make testnet-wipe`”, which will wipe everything your node has done and start over.
  * **To run a mainnet node, simply run “`make mainnet`” instead of “`make testnet`”.**
    * Note that this will leverage the `mainnet.docker-compose.yml` instead.<br>
* **Access your node’s frontend.** Once your docker-compose is running, you can access your node using its reference frontend at `yournodesdomain.com:8080`. To properly access your frontend, you need to visit this address and set a key-value in local storage that tells your frontend the address of your node’s API endpoint.\
  \
  The key is “`lastLocalNodeV2`” and the value should be `"yournodesdomain.com:18001"` if you ran `make testnet` and `"yournodesdomain.com:17001"` if you ran `make mainnet`. \
  \
  See screenshot below for an example from the video. Once you set this, you can access your node’s frontend at `yournodesdomain.com:8080` and tweak it via the Admin panel. \
  \
  We will have improved docs on this soon!

  <figure><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXeRvJt8rx9tySY4EmhBtL8bHzy188bGFpu0bMxAfP4xNo4Pi_y9RFZDU4wzwXuLuJdj2SjMU_IeHA9IMDgb1powoW3FkSBof55cjlm83_qXaFF5wmokx2ecuHEfvB6rrSHnIdIi5jg7QCMyCnjVLZWFJZ0M?key=Oj9nXlPuOUnCJ5YUj2muHA" alt=""><figcaption><p>Update the value for "lastLocalNodeV2"</p></figcaption></figure>

### Node Setup (From Source) <a href="#h.vdjummgkx9ho" id="h.vdjummgkx9ho"></a>

TODO: Make this more clear and show a video doing this on a new node from scratch.

* [Go through this tutorial and checkout all the repos listed](https://www.google.com/url?q=https://docs.deso.org/deso-tutorial-build-apps\&sa=D\&source=editors\&ust=1720503195012057\&usg=AOvVaw13zbuDPqRkvR_9Ha5Kj3X_)
* After that you should have \*at least\* the following repos locally:
  * core
  * backend
  * frontend
* cd backend/scripts/nodes
* For mainnet run `./n0`. For testnet run `./n0_test`
* If you want, you can play with all the flags in those files to get different behavior.

If you’re interested in a walkthrough of the code, check out our [Architecture Overview](https://www.google.com/url?q=https://docs.deso.org/deso-repos/architecture-overview\&sa=D\&source=editors\&ust=1720503195012546\&usg=AOvVaw2ufsWYKUDyP-dbH6q8Kvoe)

## Running a Validator <a href="#h.79y85q98fhdi" id="h.79y85q98fhdi"></a>

A validator on the DeSo network is responsible for voting on new blocks as they’re proposed, and for proposing valid blocks when it’s their turn to be leader. Validators can be staked to by anyone on the network, and they earn a commission on the rewards that accrue to all of the $DESO that is staked to them.

Below are the instructions for setting up a validator. We assume you’ve read through how to set up a node in the previous sections:

* Testnet only:
  * First, pick up some free testnet $DESO
  * Visit [https://test.deso.org](https://www.google.com/url?q=https://test.deso.org\&sa=D\&source=editors\&ust=1720503195012989\&usg=AOvVaw0yavsq_hnUcwBSYYGerden)
  * Create an account
  * When creating an account you can enter your phone number to get 1 free testnet $DESO from the faucet
  * Note that testnet $DESO does not have any value outside of the test environment!<br>
* Now that you have $DESO, head to the block explorer
  * [Testnet link](https://www.google.com/url?q=https://explorer-testnet.deso.com/\&sa=D\&source=editors\&ust=1720503195013414\&usg=AOvVaw1ZE5UyvxPH8-MdyKQYCEQK)
  * [Mainnet link](https://www.google.com/url?q=https://explorer.deso.com/\&sa=D\&source=editors\&ust=1720503195013581\&usg=AOvVaw1vRlIzJY12OfqfJySci5dx)<br>
* Login to the block explorer by hitting “Login” in the top-right and selecting the account that holds your $DESO<br>
* After logging in, select Validators > Stats from the top menu
  * Note the APY at the top. This amount will change depending on how many people are staking<br>
* Register your validator. To register your validator, hit the “Run a Validator” button in the top right.

  <figure><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXeYyA0yMIUyfyLUP83z3mHYTbx5Rlx8bP0aMbKywzKdVMPoNZbRkao2BKICEjL9mxDcgCA-fgN0PDMcKv-XzWt1O-pOaXX2LkYDW74fyyH29cM86aJqRAKznsxd7gzBoJyNR9x84Ez0x33UKVzwoUNP4KPJ?key=Oj9nXlPuOUnCJ5YUj2muHA" alt=""><figcaption><p>Click Run a Validator<br></p></figcaption></figure>
* Registering your validator consists of broadcasting a transaction on-chain signed by your validator private key. The UI in the block explorer helps you form this transaction, but you can also do it permissionlessly with a script if you prefer. This tutorial will focus on using the UI to do it.<br>
* **Getting all of the fields right.** The registration transaction requires a bunch of fields shown on the “Run a Validator” page. We walk through each one and how to set it up below.<br>
  * **Add Domain.**
    * **Static IP (covered in the video tutorial).** First, your validator must have a static IP address for your node and it should ideally have a domain associated with that IP address. AWS and Google Cloud make it very easy to have a static IP, but setting one up for your home is easy as well (and fun), although you will have to call your cable provider to do it.<br>
    * **Registering a domain (covered in the video tutorial).** Once you have an IP address associated with your node, you can associate a domain with it simply by setting a single A record on your DNS settings just like you would for a normal website. See sirstakesalot.com for an example.<br>
    * **Default ports.** By default, your testnet node will expose a protocol port on `18000` and an API port on `18001`. For mainnet, the default ports are `17000` and `17001`.
      * The protocol port is the one that matters for consensus, as it’s what nodes use to connect to you and send you blocks. The API port is mainly used to power a frontend that you can use to manage your node.
      * When you register your validator, you need to include the protocol port, and so your registration string will look like “example.com:18000” for testnet or “example.com:17000” for mainnet.
      * You can also change the ports to whatever you want, just as long as the string in your registration transaction matches what your node is actually doing.<br>
    * **Run your node and make sure it’s exposed to the outside world.** Once you have your static IP and domain, you can use the validator registration UI to check your node’s connection. \
      \
      You can also use this curl command, but replace your domain and port with what your node is running on (for mainnet, node you must use port `17001`):

      * `curl` [`http://sirstakesalot.com:18001/api/v0/health-check`](https://www.google.com/url?q=http://sirstakesalot.com:18001/api/v0/health-check\&sa=D\&source=editors\&ust=1720503195014735\&usg=AOvVaw3aV-kYEYnFUyvUgsAV-0hh)
        * Note this is querying the API port `18001` not the protocol port. This is usually fine but the UI will actually check your protocol port.

      <figure><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXfkzzOxoK5TSPn4i3VvtCQb0RZftfNxyqQMSwlsLsrvxZHrtCpbfpBk2FRAJT_LaKXXLcuAAK2_Gs1UJWr9O-SOZqDfWjY5wQlfRZ8Ej8Xr02aSyj0DY-SjiqqKL4VyBXeVUwuFn0XmIFnRjsvd_4sXmLhk?key=Oj9nXlPuOUnCJ5YUj2muHA" alt=""><figcaption><p>Click "Test"<br></p></figcaption></figure>
  * **Setting up your voting public key.** Once your validator is reachable by the outside world, you need to set up your voting public key. This is the key that you’ll use to sign consensus messages like votes or block proposals. Below we explain how to generate this keypair.<br>
    * **First, generate a seed.** Your validator keypair can be generated from an ordinary 12-word seed phrase, just like the one you get on any DeSo app. You can either use one that’s associated with an existing profile or a brand new one that you designate just for PoS messages.<br>
    * **Next, get the public key and authorization bytes.** Once you have a seed phrase you like, you need to use [this validator key generator](https://www.google.com/url?q=https://github.com/deso-protocol/validator-key-generator\&sa=D\&source=editors\&ust=1720503195015440\&usg=AOvVaw2nifvX4og_kZSxbPNRd3W3) script to generate a voting public key and a voting authorization, which you will enter into the UI.<br>
      * Why is this necessary? The reason is that your validator keys are BLS keys, while your standard DeSo keys are ECDSA private keys. BLS keys allow for “signature aggregation,” which is needed by Revolution PoS, and hence even if you use the same seed for both your DeSo account and your validator, you will need to use this script to generate a voting public key that is distinct from your DeSo public key.<br>
      * The other benefit of having a script to generate the pubkey+authorization is that it allows for totally offline generation of validator pubkey and authorization, which is needed by custodians and exchanges that want to stake.<br>
    * **Set POS\_VALIDATOR\_SEED in your config.** Note that there is one missing step in the video, which is you need to set your `POS_VALIDATOR_SEED` in the `testnet.docker-compose.yml` or `mainnet.docker-compose.yml` file to be **equal** to the seed you used with the [validator key generator](https://www.google.com/url?q=https://github.com/deso-protocol/validator-key-generator\&sa=D\&source=editors\&ust=1720503195015904\&usg=AOvVaw1BfinK5cUp9norf8mSS4zI). This is how your validator becomes capable of signing blocks with its bls keypair.<br>
  * **Commission.** This is what percentage of the staking rewards you get to keep. A lower commission will attract more people to stake with you.<br>
  * **Delegated stake.** If you disable this, nobody will be able to stake to your validator except you. This is useful if you just want to run a validator to manage your own stake.<br>
  * **Announcements and Discussion Telegrams.** Please join these telegrams to get your passwords! You can register without joining these, but then you may miss out on critical updates.
    * [Discussion Telegram](https://www.google.com/url?q=https://t.me/deso_pos_discussion\&sa=D\&source=editors\&ust=1720503195016353\&usg=AOvVaw0hw11KFldrvc2HpCsav4_X)
    * [Announcements Telegram](https://www.google.com/url?q=https://t.me/deso_pos_announcements\&sa=D\&source=editors\&ust=1720503195016567\&usg=AOvVaw3ZSbA4mvIz-yEnYfrmoTRo)<br>
* **Time to register!** Once you’ve filled in all the fields, hit the “Register Validator” button. This will construct and submit a transaction that links your voting public key with your node’s public domain+port and your DeSo profile (the one that you’re logged-in with). Linking all of these together on-chain makes it so that 1. other nodes can connect to your validator node and 2. people can stake to your validator node. Exciting!<br>
* **Keeping your validator up.** If your validator is down for a 12-hour period, it will be “jailed.” You will see this in the validator UI.\
  \
  To **unjail** your validator, you will need to go back to the [validator registration page](https://explorer.deso.com/validator-settings) after you’ve fixed your node and hit “Unjail Validator.” \
  \
  Note that there will be a cooldown of a few hours before your validator is able to vote in consensus again.

Once your validator is registered, it should appear immediately on the validators page. You can then stake to it following the prior instructions.


# What is Openfund?

Openfund is the first fully on-chain order-book spot DEX. Imagine if Coinbase or Binance were fully on-chain, with fully transparent on-chain trading and deposits, zero FTX risk, and no user experience trade-offs. This has been the holy grail for crypto from the beginning, and it has not been possible until Openfund, built fully on the DeSo Blockchain.

## Openfund’s Key Advantages

<figure><img src="/files/oe4wsXnLCT6CCbozU9JE" alt=""><figcaption></figcaption></figure>

Below, we explain each of Openfund’s key advantages, referenced in the table above, with direct comparisons to other platforms:

1. **Fully on-chain order-book.** Existing “liquidity pool” approaches like Uniswap or Raydium are designed to run efficiently on legacy blockchains, which do not have the ability to store and match orders efficiently on-chain, and thus do not give users the full power of an order-book DEX. Openfund, built on the next-generation [DeSo blockchain](https://deso.com), has been designed from the ground up to give users the full power of an order-book, exactly like the experience of using Coinbase or Binance, but with everything happening 100% on-chain. And we mean everything: Order placement, order matching, and even our advanced AMM order placements are all fully on-chain. What’s more, the DeSo blockchain, which powers Openfund, is 100% open-source, and anyone can audit the DEX code for full transparency (see [the DeSo core repo](https://github.com/deso-protocol/core), which contains all the key DeSo node code, with emphasis on [the order-book code here](https://github.com/deso-protocol/core/blob/main/lib/block_view_dao_coin_limit_order.go)). \
   \
   *The charting technology is provided by* [*TradingView*](https://www.tradingview.com/)*. Learn* [*how to use theTradingView Stock Screener*](https://www.tradingview.com/screener/)*.*
2. **Cross-chain spot trading.** Today, if you want to convert one unit of BTC to one unit of ETH on a DEX, it would not be possible without using complex, slow, and high-risk bridging products (often taking [whole days](https://www.lcx.com/info/faq/others/how-do-you-withdraw-from-base/) to settle). Perpetuals platforms like dydx and Hyperliquid allow users to speculate on asset prices, but they do not give users the ability to actually cashout to anything other than USDC (thus you cannot use them to actually “spot” trade one unit of crypto for another). What’s more, going long or short on perpetuals exchanges will subject you to funding rate fees, often 30% annually or higher, making it very expensive to maintain positions for long periods of time, especially if there’s a lot of volatility. In contrast, Openfund is the first DEX where one unit of Bitcoin can be directly traded for one unit of Ethereum (and many other currencies including SOL, USDC, SUI, DESO, and AVAX), without any hidden fees or perp funding rates because you actually own the underlying asset. No matter how popular perpetuals and derivatives become, there will always be a need to settle the actual underlying assets. As such, Openfund can serve as the unified “settlement layer” for all of DeFi, a role that was previously monopolized exclusively by centralized exchanges. This is made possible by a tight integration with [HeroSwap](https://heroswap.com), which supports near-instant cash-in and cash-out of fully on-chain assets.
3. **Fully on-chain deposits.** When using a Centralized Exchange (CEX), you have to trust that they are holding the deposits they say they are holding, and, as we saw with FTX, this can go very badly. In contrast, with Openfund, every deposit is fully on-chain, and verifiably backed by the exact amount of crypto held by each user. This is made possible by wrapped assets powered by the DeSo blockchain, such as [USDC-DESO](https://openfund.com/profile/USDC?tab=Holders), [BTC-DESO](https://openfund.com/profile/BTC?tab=Holders), [ETH-DESO](https://openfund.com/profile/eth?tab=Holders), and [SOL-DESO](https://openfund.com/profile/sol?tab=Holders). Each wrapped currency has fully on-chain social information attached to it, thanks to DeSo, including a profile description with links to backing wallets, and a list of holders, who also each have their own on-chain social profile. When you deposit a currency on Openfund, one unit of your currency goes into the fully-transparent and on-chain backing wallet, and you receive one unit of wrapped currency on DeSo, held in full self-custody. This wrapped currency can be used to trade on the fully on-chain DEX, and swapped back anytime within Openfund itself. At any time, users can verify that their assets are 1:1 backed simply by clicking through the backing wallets listed in the wrapped asset’s on-chain social profile (again, only possible thanks to DeSo’s on-chain social features). Exchanging BTC for ETH on Openfund is as simple as depositing BTC, swapping for ETH on the order-book DEX, and then cashing out, just like a centralized exchange, but with full transparency, and full self-custody the whole time. In addition, using DeSo wrapped assets is nearly gas-less. Over time, people may even come to prefer holding a DeSo-wrapped asset over the real thing because of these advantages, combined with the level of transparency around backing assets.
4. **Unique human-readable on-chain tickers.** Today, finding the right token on a DEX is an awful user experience, often requiring users to copy-paste contract addresses into search bars. What’s more, users frequently get tricked into buying a “doppleganger” token that looks like the real one, but that was actually created by a scammer who steals their funds. Imagine if, instead of identifying tokens by contract addresses, every token had a unique ticker, username, and description attached to it fully on-chain. This is what the DeSo blockchain enables, thanks to its fully on-chain social features. You’ll never have to enter a contract address to find a token on Openfund: The name of the token is the ticker, vastly improving the user experience and solving the doppelganger problem, especially when it comes to listing new tokens. Tokens also have fully on-chain social features that no other blockchain supports, such as the ability to make on-chain social posts, follow other users on-chain, and much more. This extra on-chain social information is attached to the token itself, and makes it easier than ever to ensure that the token you’re about to buy is the one that you think it is.
5. **One-click meme coins, instant permission-less listing, and automated market-making for new tokens.** Today, if you want to launch a new token, you not only need to convince centralized exchanges to list you, but you also need to pay market-makers millions to bootstrap liquidity for your market (only to have the market-makers dump your token the minute it lists due to lack of oversight). What’s more, because the “index price” of new tokens is highly volatile and sensitive to manipulation, perpetuals exchanges are largely unsuitable for trading newly-launched tokens, especially “long-tail” meme tokens (let alone with reasonable funding rates). Openfund changes all of this by pioneering an automated listing and liquidity-provision scheme that has been years in the making. Listing on Openfund is as easy as creating a social profile: Every wallet on the DeSo blockchain can issue tokens, which are then immediately trade-able on the Openfund order-book DEX. And because every token has a unique human-readable ticker/username, users can find new tokens much more easily. In addition, because Openfund is the first fully on-chain order-book spot DEX, it is pioneering a new kind of automated market-maker (AMM) to bootstrap liquidity. As soon as a token is launched, an automated market-maker can be configured to provide far better order-book liquidity than any centralized market-maker has previously been capable of, all with full transparency and zero conflicts of interest (with the creator earning fees on the trading automatically and seamlessly). These AMMs are currently running on the [$btc](https://openfund.com/trade/BTC), [$eth](https://openfund.com/trade/ETH), [$sol](https://openfund.com/trade/SOL), [$openfund](https://openfund.com/trade/openfund), and [$deso](https://openfund.com/trade/deso) markets. But they will be available to all new currencies that users launch on the DeSo blockchain via the launch of [Focus](https://focus.xyz), DeSo’s next-generation SocialFi app. Our new AMMs will initially be configurable exclusively on Focus to promote its launch, but they will be accessible to all DeSo tokens soon after (and all tokens launched on Focus will be trade-able on Openfund, thanks to the DeSo blockchain). Put simply, Focus can be viewed as a new launchpad for tokens, with Openfund serving as the order-book exchange for trading. What’s more, because everything is run on the open-source DeSo blockchain, there is nothing stopping anyone from creating alternative launchpads and AMM’s, all of which will result in tokens trade-able on Openfund, thanks to the fact that everything is on-chain.
6. **Full self-custody.** When you use a centralized exchange like Coinbase or Binance, they can freeze your assets or limit access to your account at any time. In contrast, this is impossible on Openfund because all of your assets are fully on-chain. Whether you are holding wrapped or unwrapped assets, nobody can freeze the coins in your account or limit your access to them in any way. Almost everyone who’s used a centralized exchange over the years knows what it feels like to lose access to your account, and to have to spend weeks convincing support staff to give you back access to money that’s supposed to be yours in the first place. This can never happen on Openfund: Your keys, your coins.


# Openfund Tokenomics

Like most projects in crypto, Openfund has a token, called $openfund, which trades [directly on Openfund itself](https://openfund.com/trade/openfund) (with a novel order-book AMM to provide ample liquidity). However, unlike most tokens in crypto, the Openfund platform uses 100% of trading fees to buy and burn $openfund, providing a fundamental floor on its market value. In this section, we describe the exact economics of the $openfund token, how it was initially distributed, and how its governance works.

### Trading Fees

Openfund’s fundamental value proposition is simple: Charge a fee on DEX trades, and use 100% of the fees to buy & burn $openfund tokens. [An on-chain vote](https://openfund.com/d/openfund?proposalId=0f304260bab6a3ff12ed2d54ae2d17ffd012005feb5a53ea529b22878a15ea5a) already activated the fee switch, and set the initial trading fees to 10 basis points, competitive with other spot exchanges. By the time these docs go live, the fees should be active on all markets, and the buy & burn should be started. In addition, note that DEX fees for Openfund trades accrue to $openfund irrespective of whether tokens were launched on Focus or some other launchpad, thanks to the fact that all trading is fully on-chain.

How much in fees could Openfund earn? It is useful to consider how meaningful this can be, and what this could mean for the floor value of the $openfund token (noting that tokens in crypto typically trade at a significant premium to their fundamental floor value).

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfwVcRkaWUPRIGlkwPjHSZ_eBQvdKBMtBFoFNYx5aU1OUAW84effs4QBPvCET7tPSL_yYuW1-WGxTna-hzvDuzLnRVKjrUOkY8pVXbYKl2vb2mnkklUlPoVVr9jq3F47QFpBV-B?key=mP6OxBf72TMpy8OjbBFZFR5I" alt=""><figcaption></figcaption></figure>

Importantly, people tend to under-estimate how much bigger the market for a decentralized order-book spot exchange can be when compared to a centralized one. Until today, all decentralized spot exchanges have operated by the vastly inferior liquidity-pool model, on chains with high gas fees and legacy infrastructure like Ethereum and Solana, thus making it difficult for them to take market share from centralized exchanges like Binance. Meanwhile, while they have invested in special-purpose blockchains, perpetuals exchanges like DYDX and Hyperliquid don’t even support cashout to anything other than USDC, have high funding rates, and will never support long-tail tokens or instant permission-less listing. Openfund is truly the first platform that matches centralized and decentralized exchanges feature-for-feature, creating the first truly global order-book that all of the world’s liquidity can easily and seamlessly access. If Openfund is successful, it is quite possible that all tokenized assets, including real-world assets, will eventually transition to being traded on Openfund, expanding the market for trading tokens far beyond what it is today.

### Token Supply and Distribution

Nobody was ever given $openfund tokens for free, including the team. There was no team allocation. Every single initial holder of $openfund had to purchase their tokens for DESO during a pre-sale event in 2022 that was completely open to the public. In that public pre-sale event, the price of $openfund was approximately 0.001 DESO per token, and thousands of people participated, resulting in approximately \~90k DESO being committed, and [\~95M $openfund tokens in circulation](https://openfund.com/d/openfund) (the same as is in circulation today).

Of the DESO committed during the $openfund public pre-sale event, none was kept by the team or even used to develop the project. Instead, 100% of the DESO raised was committed to support a “floor bid” of 0.001 DESO per $openfund token. This floor bid commitment is still in place today, and can be partially seen on the order-book on [the $openfund market](https://openfund.com/trade/openfund) if you scroll down far enough. However, the order placed on the DEX is only a portion of the total committed. The remainder was allocated to be staked [via an on-chain vote](https://openfund.com/d/openfund?proposalId=bf43bafd6c8980e5dc6c36eaa79d6c3b4b664c913e959d3eab2e1198e9ba2682) (on-chain voting is discussed in the governance section). Regardless, the DESO committed during the initial pre-sale event is fully committed to the holders of $openfund tokens. Later on, it can even be allocated to a buy-and-burn by an on-chain vote if desired.

There are no plans to increase the supply of $openfund, and doing so would require passing an on-chain vote, with a plurality of token-holders voting yes, and explicitly approving the usage of the new tokens (on-chain voting is discussed in the governance section). What’s more, there is no $openfund in circulation other than the amount that was initially purchased, and all tokens have been fully unlocked from day one. There are no lockup schedules, and therefore no major holders waiting to dump as soon as their tokens become liquid. The circulating supply is equal to the fully-diluted supply.

The total supply and current distribution of tokens can be seen [on Openfund itself](https://openfund.com/d/openfund) (scroll to “Holders”) or [on any DeSo node](https://node.deso.org/u/openfund?feedTab=Following\&tab=dao). We note that every holder has an on-chain social profile, with the ability to message them on-chain as well, thanks to DeSo. No other token that we’re aware of lists so much social metadata with each of its holders, let alone gives you the ability to message them and get to know them. Just from looking at the on-chain holders list, it should be clear that no individual wallet owns more than \~20% of the total supply, and that the top holder is [Nader Al-Naji](https://www.linkedin.com/in/nader-al-naji-86b14a3a), the creator of the DeSo blockchain, who purchased his tokens on the exact same terms as everyone else.

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdhkN5PVXJo1OtIFZGp0PmLaO16K2ZpbH6UfjBnAwRcGUiOe_sDm-iTk7I7Yy_x-8CHHDri9-v5mTpgV6COqwMPtfbm7bd_fQoAuFVUH6Bm0J-6Ppi7HAgafMIitLLVmiJpOrvzPg?key=mP6OxBf72TMpy8OjbBFZFR5I" alt=""><figcaption></figcaption></figure>

All this raises an important question: If the team has no allocation, and if the team receives none of the committed DESO, then what motivates the team to continue developing the Openfund platform? There are two reasons: First, although the team was not given an initial allocation, they were allowed to purchase tokens from the public pre-sale event at the same price as everyone else. This resulted in a decent ownership percentage for the team, noting that the vast majority is owned by non-team individuals. In addition, however, the team developing the Openfund platform is the same team that is developing the DeSo blockchain, which powers Openfund. The success of Openfund will almost certainly result in the success of the DeSo blockchain, and the team holds a significant percentage of DESO as well (though again noting that no individual owns more than 20% of DESO). As such, while the team has some exposure to Openfund through token ownership, the team is further aligned by the fact that Openfund is a positive externality for the DeSo ecosystem. This motivation has clearly resulted in vast improvements to the platform since its initial launch.


# Openfund Governance

The Openfund platform is essentially a frontend client on the DeSo DEX, which powers Openfund’s fully on-chain order-book functionality.

Changes to the DeSo blockchain happen according to upgrades to its Revolution PoS consensus mechanism, which is described in detail [here](https://revolution.deso.com/) and [here](https://docs.deso.org/deso-validators/run-a-validator), with all current validators and their staking percentages listed on [the DeSo block explorer here](https://explorer.deso.com/validators). In simple terms, anyone can submit an upgrade to [DeSo’s fully open-source code](http://github.com/deso-protocol/core), but an upgrade to the DeSo blockchain goes through only if 2/3rds of the validators (weighted by stake) upgrade their software before a particular block height. This is similar to how other Proof of Stake blockchains work, such as Ethereum and Solana, and it ensures that changes to the blockchain get heavy oversight and buy-in from the major economic players in the ecosystem before they go through. For the avoidance of doubt, it is impossible to upgrade the DeSo blockchain without a 2/3rds stake-weighted majority accepting the changes, noting that the DeSo blockchain is [fully 100% open-source](https://github.com/deso-protocol/core).

In contrast, Openfund is an app that is centrally managed. However, to bring the same level of oversight and buy-in that we have with DeSo to the Openfund platform, we have a built-in on-chain proposal mechanism that we have been using to approve all major decisions. Although not strictly binding, since decisions are recorded on-chain but not enforced on-chain, the proposal mechanism makes it easy for the core team to get the buy-in of the token-holders before moving forward with a major change. All past proposals can be seen [here](https://openfund.com/d/openfund) in the proposals tab, including the fee switch activation, and the core team does not ever intend to make a major change to the platform without first getting a plurality of token-holder-weighted consensus on the decision (with the exception of critical security issues that may arise and require quick action). The core team takes token-holder buy-in especially seriously where economic issues are concerned.


# Algorithmic Trading

The Openfund platform is essentially a frontend client over the DeSo DEX, which powers its order-book functionality. As such, placing and managing orders on Openfund amounts to constructing and submitting transactions to the DeSo blockchain, which can be done totally permission-lessly, just like submitting a transaction to the Bitcoin network. In this section, we go over how to construct and submit transactions, and walk through the creation of a simple market-making bot.

Read the next section to learn how to start algorithmic trading with the DeSo Python SDK.


# The DeSo Python SDK

Everything you need to construct, sign, and submit transactions is in [the DeSo Python SDK](https://github.com/deso-protocol/deso-python-sdk). This is an advanced library that makes it extremely easy to do all of DeSo’s basic (and not-so-basic) transaction types.

The best way to learn is to simply go through the README and run the code. Once you’ve gotten everything to a “SUCCESS” status, you can proceed to the challenges, which simultaneously walk you through how to build an advanced market-making bot, as well as advanced social bots.

Read the next sections to learn how to get help from the community and test your knowledge.


# Getting Help from the Community

Up-front, if you ever run into trouble and want to talk to someone, the [DeSo PoS Discussion Telegram Channel](https://t.me/deso_pos_discussion) is a great resource. Everyone who runs a node is in there, as well as members of the DeSo core team. Many there are generally very knowledgeable on the ins and outs of the DeSo blockchain, and super helpful to new users trying to understand what’s going on. We used to run a Discord, but we’ve found a simple dev-focused Telegram channel works better.

If you ever run into issues while doing a swap, the [HeroSwap Support](https://t.me/heroswap) channel can help you. This shouldn’t be needed but we include it here for completeness.


# Creating DeSo Testnet Accounts

First, if you’re going to be writing a trading bot, it is best to familiarize yourself with the DeSo node testnet UI, node [accessible here](https://test.deso.org/), and the Openfund testnet UI, [accessible here](https://dev.openfund.com/trade). This will allow you to do everything with “fake money” so that you don’t put capital at risk until you’re sure everything is working properly.

To set up a testnet account, simply execute the following steps:

1. Visit <https://test.deso.org>
   1. This is the reference node for testnet that most developers get started on when testing. Note that anyone can run a DeSo node by following the instructions in [the core repo](https://github.com/deso-protocol/core), this just happens to be a fairly reliable one.
2. Create an account
   1. Note that DeSo wallets are managed locally in your browser. The DeSo wallet works almost exactly like MetaMask, only it doesn’t require the installation of a Chrome extension, and it supports much more granular and transparent permissions at an app level. This means that creating a wallet on one app results in that wallet being accessible to any other DeSo app as long as permissions are confirmed, including [Openfund](https://openfund.com), [Diamond](https://diamondapp.com), and [Focus](https://focus.xyz) (noting these are mainnet links, not testnet ones, so your testnet wallet won’t be accessible there).
      1. Note that when you use an app, a “derived key” is issued that has much more limited permissions than your master key, which you have to accept before using the app. This allows you to use an app without having to hit “confirm” on low-value transactions (e.g. making posts or liking posts) while being 100% sure the app can’t steal funds.
   2. We recommend always using seed phrases for test accounts, as that tends to be easier to manage. You can use one seed phrase and create new accounts with different indexes by hitting “add account” in the wallet.
3. When creating an account you can enter your phone number to get 1 free testnet $DESO from the faucet
   1. Note that testnet $DESO does not have any value outside of the test environment!
   2. If you don’t want to enter your phone number, some apps use the advanced captcha flow, such as [dev.openfund.com](http://dev.openfund.com). Eventually this flow will be integrated back into the reference node.
4. Once you have an account with starter DESO, you can visit the following links to test things:
   1. Testnet explorer: <https://explorer-testnet.deso.com>&#x20;
      1. Here, you can login and stake your DESO if you want.
   2. Testnet Openfund: <https://dev.openfund.com/trade>&#x20;
      1. Here, you can place orders and use the inspector to see what transactions are being constructed and submitted to the DeSo blockchain.

For a reference on all useful testnet links, including the testnet block explorer, [see here](https://docs.deso.org/deso-validators/run-a-validator#h.gcb427f1q4hl).

For tips on creating lots of **mainnet** accounts with starter DESO in them, [see here](https://docs.deso.org/deso-tutorial-build-apps#tip-for-creating-lots-of-test-accounts).

For a primer on building DeSo apps, [see here](https://docs.deso.org/deso-applications). Useful as a reference, or if you find something confusing in this guide.

<br>


# Debugging Tips and Code Walkthrough

The DeSo blockchain is written in the Go programming language for high performance, and its code is 100% open-source, with the [core](https://www.github.com/deso-protocol/core) and [backend](https://github.com/deso-protocol/backend) repos being the most important for understanding the node architecture and transaction construction respectively. The core repo represents all of the most critical code for processing transactions, while the backend repo mostly consists of REST endpoints that you can call to construct and submit transactions. If you’re curious about them, it is useful to load both repos into your IDE to explore them (we recommend VSCode or Goland; our team uses both). This being said, even though the DeSo blockchain is written in Go, you don’t have to know Go in order to construct and submit transactions! In this section, we show you how use a simple Python library to construct, sign, and submit all of the basic order management transactions you’ll need in order to write a trading bot.

The Openfund client constructs, signs, and submits the exact same transactions you’ll be working with in this tutorial ([mainnet client](http://openfund.com/trade), [testnet client](https://test.deso.org/)). This means that, if you’re ever unsure of how to do something, you can simply open up the Openfund trade page, open up the inspector, go to the network tab, and look at how Openfund is constructing and submitting the transaction (lookup a tutorial on how to use the web inspector to do this if you’re not familiar with this kind of thing). The only thing you will not be able to get from this process is the signing of the transaction, which we’ll cover in this tutorial, and which the Python library already implements for you. In addition to using Openfund to inspect things, you can also use the reference DeSo node ([mainnet node](https://node.deso.org/), [testnet node](https://test.deso.org/browse?feedTab=Global)), which supports an even larger set of transactions, including making on-chain posts, following users on-chain, and much more. When Focus launches, you’ll have even more transaction types to explore there as well ([focus mainnet](http://focus.xyz), [focus testnet](http://beta.focus.xyz)). Often, when the core team adds new transaction types, they are tested on the reference DeSo nodes first, and so those are often the most “complete” places to see how transactions work. For the purposes of this tutorial, you can see how tokens are minted, burned, and sent on the “DAO” tab of the reference client, for example. For all trading transactions, though, Openfund is the best place to inspect them.

In addition, if you want to be more “hard-core,” you can read the DeSo node code itself to see how the transaction you’re trying to construct actually gets processed under-the-hood. All endpoints supported by the reference backend have a variable of the form RoutePath\*, such as [RoutePathUpdateProfile](https://github.com/deso-protocol/backend/blob/8a00fd811dd2faae78f9363b4efe7fc29d3617a6/routes/server.go#L55). If you look for usages, you will find them link dot the RoutePath with a format [like this](https://github.com/deso-protocol/backend/blob/8a00fd811dd2faae78f9363b4efe7fc29d3617a6/routes/server.go#L783). This allows you to trace what an endpoint is doing (useful if you get a weird error). The DeSo open-source node code also provides Go functions responsible for constructing transactions, all of which follow the general naming scheme Create\*Txn, such as [CreateUpdateProfileTxn](https://github.com/deso-protocol/core/blob/877178a9713604e8223ff33395ff15b62f2a2bb7/lib/blockchain.go#L3661), and you will generally see one of these functions if you trace a RoutePath for a txn construction endpoint. Every transaction type supported by the DeSo blockchain implements a \_connect function, such as [\_connectUpdateProfile](https://github.com/deso-protocol/core/blob/877178a9713604e8223ff33395ff15b62f2a2bb7/lib/block_view.go#L1973), which is what is called when a node on the network actually processes your particular transaction. To see all of the transaction types supported by the DeSo blockchain, you can simply search for all of the \_connect functions in [the core repo](https://github.com/search?q=repo%3Adeso-protocol%2Fcore+_connect\&type=code), and then find the Create function that calls it to see how it’s constructed as well (which could be in the [backend repo](https://github.com/deso-protocol/backend)). While this isn’t strictly necessary information, it can be useful if you are unsure why your transaction is being rejected by the network, or if you want to see what parameters you can provide to a particular transaction type. The best way to debug is to find the \_connect\* function that you’re trying to trigger, and then trace it up to the function that actually constructs the transaction to see what it’s doing. In addition, if you ever get an error, you can always find it in the core+backend repo if you have them loaded in your IDE. So, to summarize:

* To see all the possible endpoints you can hit to construct transactions or get data, look for RoutePath\* in the core+backend repos.
  * Find the function that gets called and trace it to see how a transaction is constructed or how data is returned.
* To see all the txn types a node can process, look for all the \_connect functions in core and read through them, or find the one for your particular transaction type.
* Create\*Txn functions are responsible for constructing transactions, and are typically called in txn construction endpoints. You will likely trace through them if you get a weird error.

The transactions we’ll be most concerned with for trading are as follows (for legacy reasons, DeSo Tokens are referred to in the code as “DAO Coins”:

* \_connectDaoCoin
  * Used to mint and burn your token, or to change transfer restrictions
* \_connectDaoCoinLimitOrder
  * Used to create market and limit orders, and to cancel orders
* \_connectDaoCoinTransfer
  * Used to transfer your token to other accounts
* We won’t cover them here, but you may also be interested in the following functions, which allow you to add yield to your coin:
  * \_connectCoinLockup
  * \_connectCoinLockupTransfer
  * \_connectUpdateCoinLockupParams

If you want, you can trace how the above functions are called all the way to the RoutePath, which will then tell you how to actually trigger them with a simple HTTP request. But it’s easier to instead inspect http requests on an existing app, like Openfund, and work “top-down” from the RoutePath, so that’s what we generally recommend. We just want to give you both options so you have the maximum ability to debug.

Whenever you’re constructing a transaction, as the next section will show you how to do, you may get a really long and hard to read error message. The key to deciphering these is to go all the way to the end and look for the RuleError that you got. For example, frequently you will have RuleErrorInsufficientBalance if you have no DESO or something like that. The RuleError should always tell you what’s going on, and be self-explanatory. But if it’s not, then you can go into the code as mentioned above and trace what’s going on. Thus is the benefit of 100% open-source software!

<br>


# Write Blockchain Bots with AI

You may have noticed that the [DeSo Python SDK](https://github.com/deso-protocol/deso-python-sdk) is a single Python file. There is tremendous value in this because it means you can simply "drop" the entire sdk into your favorite AI and ask it to write new functions for you, or to put together the existing functions in novel ways. Keep this in mind as you do the other exercises in this section. It may help to load the sdk into an AI before you begin so you're ready to ask it questions!


# Market-Making Bots

Use the [DeSo Python SDK](https://github.com/deso-protocol/deso-python-sdk) to complete the following Challenge Exercises, and build a fully-functioning market-making bot:

1. Get the market mid-price of $openfund on the openfund/deso market by using the get\_limit\_orders function. Beware of ASKs that look like BIDs, and vice versa!
2. Place a market order to buy 0.000001 DESO worth of $openfund. You should be able to do this with just your starter DESO.
3. Check your $openfund balance after doing the market order to confirm that you have the amount of $openfund that you expect to have.
4. Place a LIMIT order to BUY $openfund just below the market mid price, and a LIMIT order to SELL $openfund just above the market mid price. You should be able to do this now that you have both $openfund and $DESO from the previous step! The orders should "rest" on the book, without executing immediately. Save the order\_id from the transaction so you can manage the state of your order! The order\_id is simply the signed txn hash of the transaction you used to place the order.
5. Use get\_limit\_orders to tell if your order has been filled or not. An order will be filled when it no longer appears on the book.
6. Practice cancelling and replacing one of your orders using the sdk, and passing the order\_id from when you placed the order.
7. Write a simple routine to "flip" your buy into a sell once it's been filled (at a slightly higher price so you earn a "spread"). Do the same for your other limit order.
8. ADVANCED: Acquire $100 worth of $openfund and $100 worth of $DESO. Place 10 bids and 10 asks for $10 each around the market mid using an ATOMIC transaction.
9. ADVANCED: Write a routine to "flip" your asks to bids when they're filled (with a spread so you make some money on the volatility!). Do the same for your bids.
10. CONGRATS! If you made it this far, you are officially a market-maker on the DeSo DEX! The AMMs that power Focus and Openfund are essentially a highly-sophisticated and scaled-up version of what you just did.


# Social AI Agents

Use the [DeSo Python SDK](https://github.com/deso-protocol/deso-python-sdk) to build new kinds of entertaining (and possbly lucrative) social agents:

1. Use the sdk to create a post from your account. Running the main properly should already achieve this. Edit the text to something more fun.
2. Use the sdk to follow @nadertheory on testnet and @nader on mainnet.
3. Use the sdk to repost something from your account. A repost uses the same submit\_post but with RepostedPostHashHex set.
4. Use the sdk to comment on someone's post. A comment is just a post with a ParentPostHash set.
5. ADVANCED: Use the sdk to write a bot that queries an AI API to automatically reply to all of your posts with something meaningful and useful.
6. ADVANCED: Use the sdk to write a bot that auto-replies to anyone who comments on your post with something meaningful from your personal account.
7. ADVANCED: Use the sdk to send a paid message to someone.


# AI-Generating Your Code

Although the [DeSo Python SDK](https://github.com/deso-protocol/deso-python-sdk) has many useful features, sometimes it's easiest to create your own transaction flow from observing another app (such as Openfund or Focus). This section teaches you how to do that, and how to use AI to auto-generate your code:

1. Navigate to the "DAO Coin" tab on node.deso.org for Openfund here. Remember that "DAO Coin" is just an old term for "DeSo Token"!
2. Open the web inspector on your browser and navigate to the Network tab.
3. Filter the requests to get-hodlers-for-public-key. Click "Copy as CURL" to get the params used by the request. In addition, note "Copy Response" as we'll be using that too.
4. With the sdk loaded into your favorite AI tool, paste the result of "Copy as CURL" and the result of "Copy Response" into the chat, and ask it to add a function to get all the holders for a given token.
5. CONGRATS! You've just added a NEW FUNCTION to the sdk! You can use this process to automate anything you do on openfund.com, focus.xyz, and any DeSo app!

PS: We may have used this exact method to write some of the [DeSo Python SDK](https://github.com/deso-protocol/deso-python-sdk). Ssshh don't tell anyone! :smiling\_face\_with\_tear:




---

[Next Page](/llms-full.txt/1)

