Steem Developer logo

Steem Developer Portal - Services

Steemit.com

steemit.com endpoints

Steemit.com offers a few endpoints for getting common data. User profile and post JSON data is very convenient and simple by appending .json to your request.

Getting a particular user profile JSON:

https://steemit.com/@curie.json

User object

{
   "user":{
      "id":81544,
      "name":"curie",
      "owner":{
         "weight_threshold":1,
         "account_auths":[],
         "key_auths":[["STM69WGR1yhUdKrnzwQLDPnXrW9kaAERwHze8Uvtw2ecgRqCEjWxT", 1]]
      },
      "active":{
         "weight_threshold":1,
         "account_auths":[],
         "key_auths":[["STM5GAbbS84ViMEouJL3LKcM8VZzPejn68AfPaYaLZZDdmy98kwU5", 1]]
      },
      "posting":{
         "weight_threshold":1,
         "account_auths":[["steemauto", 1]],
         "key_auths":[["STM5cmuKw6EPkZWeVNXcZorKtattZTX5wSopcRb4xNe6VhRKjETgv", 1]]
      },
      "memo_key":"STM7ZBi61xYz1b9STE1PHcAraPXJbvafzge3AcPjcfeq4XkKtM2At",
      "json_metadata":{
         "profile":{
            "profile_image":"https://i.imgur.com/Mjewc66.jpg",
            "name":"Curie",
            "about":"Discovering exceptional content. ",
            "location":"Worldwide",
            "website":"http://curiesteem.com"
         }
      },
      "proxy":"",
      "last_owner_update":"1970-01-01T00:00:00",
      "last_account_update":"2018-02-28T14:21:24",
      "created":"2016-09-02T10:44:24",
      "mined":false,
      "recovery_account":"anonsteem",
      "last_account_recovery":"1970-01-01T00:00:00",
      "reset_account":"null",
      "comment_count":0,
      "lifetime_vote_count":0,
      "post_count":1042,
      "can_vote":true,
      "voting_power":8927,
      "last_vote_time":"2018-06-21T19:42:33",
      "balance":"24.519 STEEM",
      "savings_balance":"0.000 STEEM",
      "sbd_balance":"36.736 SBD",
      "sbd_seconds":"11732264931",
      "sbd_seconds_last_update":"2018-06-21T19:35:00",
      "sbd_last_interest_payment":"2018-06-15T14:05:03",
      "savings_sbd_balance":"0.000 SBD",
      "savings_sbd_seconds":"0",
      "savings_sbd_seconds_last_update":"1970-01-01T00:00:00",
      "savings_sbd_last_interest_payment":"1970-01-01T00:00:00",
      "savings_withdraw_requests":0,
      "reward_sbd_balance":"0.000 SBD",
      "reward_steem_balance":"0.000 STEEM",
      "reward_vesting_balance":"481.354811 VESTS",
      "reward_vesting_steem":"0.237 STEEM",
      "vesting_shares":"128367480.795804 VESTS",
      "delegated_vesting_shares":"0.000000 VESTS",
      "received_vesting_shares":"17069919.621493 VESTS",
      "vesting_withdraw_rate":"9672265.370398 VESTS",
      "next_vesting_withdrawal":"2018-06-24T14:01:51",
      "withdrawn":0,
      "to_withdraw":"125739449815180",
      "withdraw_routes":0,
      "curation_rewards":79730650,
      "posting_rewards":168964559,
      "proxied_vsf_votes":["1753316906111", 0, 0, 0],
      "witnesses_voted_for":1,
      "last_post":"2018-06-21T18:06:57",
      "last_root_post":"2018-06-19T13:16:15",
      "average_bandwidth":"540385456623",
      "lifetime_bandwidth":"33717478000000",
      "last_bandwidth_update":"2018-06-21T19:42:33",
      "average_market_bandwidth":"83841450748",
      "lifetime_market_bandwidth":"8042800000000",
      "last_market_bandwidth_update":"2018-06-19T04:21:42",
      "vesting_balance":"0.000 STEEM",
      "reputation":"418378051905700",
      "transfer_history":[],
      "market_history":[],
      "post_history":[],
      "vote_history":[],
      "other_history":[],
      "witness_votes":["curie"],
      "tags_usage":[],
      "guest_bloggers":[]
   },
   "status":"200"
}

Getting a particular post JSON:

https://steemit.com/curation/@curie/the-daily-curie-12-13-feb-2017.json

Post object

{
   "post":{
      "id":1720643,
      "author":"curie",
      "permlink":"the-daily-curie-08-09-jan-2017",
      "category":"curation",
      "parent_author":"",
      "parent_permlink":"curation",
      "title":"The Daily Curie (08-09 Jan 2017)",
      "body":"<center>https://s29.postimg.org/dgtsfe7if/curie2.png</center>\n## Introduction\n[Curie](https://steemit.com/steemit/@donkeypong/announcing-project-curie-bringing-rewards-and-recognition-to-steemit-s-undiscovered-and-emerging-authors)  is a commu ...",
      "last_update":"2017-01-09T12:20:15",
      "created":"2017-01-09T12:20:15",
      "active":"2017-01-11T22:44:57",
      "last_payout":"2017-02-09T14:40:54",
      "depth":0,
      "children":36,
      "children_rshares2":"0",
      "net_rshares":0,
      "abs_rshares":0,
      "vote_rshares":0,
      "children_abs_rshares":0,
      "cashout_time":"1969-12-31T23:59:59",
      "max_cashout_time":"1969-12-31T23:59:59",
      "total_vote_weight":0,
      "reward_weight":10000,
      "total_payout_value":"0.000 SBD",
      "curator_payout_value":"0.000 SBD",
      "author_rewards":0,
      "net_votes":519,
      "root_comment":1720643,
      "mode":"archived",
      "max_accepted_payout":"0.000 SBD",
      "percent_steem_dollars":10000,
      "allow_replies":true,
      "allow_votes":true,
      "allow_curation_rewards":true,
      "url":"/curation/@curie/the-daily-curie-08-09-jan-2017",
      "root_title":"The Daily Curie (08-09 Jan 2017)",
      "pending_payout_value":"0.000 SBD",
      "total_pending_payout_value":"0.000 SBD"
   }
}

SBDS

sbds is a tool for easily querying the data of the Steem Blockchain.

While providing direct interfaces to several pluggable storage architectures that may be used for querying the blockchain, sbds may also be used as a lower level API upon which other applications can be built.

Docker Hub

docker run -d steemit/sbds

Python 3

pip3 install -e git+git@github.com:steemit/sbds.git#egg=sbds

Examples

Stream blocks 1 to 3450000 from our dev S3 bucket

sbds checkpoints get-blocks s3://steemit-dev-sbds-checkpoints/gzipped --start 1 --end 3450000

Stream blocks 8000000 to the last block from your local copy of our S3 bucket

sbds checkpoints get-blocks /home/ubuntu/checkpoints/gzipped --start 8000000

Stream all blocks from your local copy of our S3 bucket

sbds checkpoints get-blocks /home/ubuntu/checkpoints/gzipped

Routes

Coming soon.

jussi

A reverse proxy that forwards json-rpc requests.

Jussi is a custom-built caching layer for use with steemd and other various services (such as SBDS).

The purpose of this document is to help developers and node operators set up their own jussi node within a docker container.

Intro

Jussi is a reverse proxy that is situation between the API client and the steemd server. It allows node operators to route an API call to nodes that are optimized for the particular call, as if they are all hosted from the same place.

Sections

Installation

To run jussi locally:
git clone https://github.com/steemit/jussi.git
cd jussi
docker build -t="$USER/jussi:$(git rev-parse --abbrev-ref HEAD)" .
docker run -itp 9000:8080 "$USER/jussi:$(git rev-parse --abbrev-ref HEAD)"

Kitematic Example jussi in a docker container as seen from Kitematic for macOS.

Try out your local configuration:
curl -s --data '{"jsonrpc":"2.0", "method":"condenser_api.get_block", "params":[8675309], "id":1}' http://localhost:9000

See: Running Condenser, Jussi and a new service locally + adding feature flags to Condenser


Adding Upstreams

The default DEV_config.json is:

{
   "limits":{"blacklist_accounts":["non-steemit"]},
   "upstreams":[
      {
         "name":"steemd",
         "translate_to_appbase":false,
         "urls":[["steemd", "https://steemd.steemitdev.com"]],
         "ttls":[
            ["steemd", 3],
            ["steemd.login_api", -1],
            ["steemd.network_broadcast_api", -1],
            ["steemd.follow_api", 10],
            ["steemd.market_history_api", 1],
            ["steemd.database_api", 3],
            ["steemd.database_api.get_block", -2],
            ["steemd.database_api.get_block_header", -2],
            ["steemd.database_api.get_content", 1],
            ["steemd.database_api.get_state", 1],
            ["steemd.database_api.get_state.params=['/trending']", 30],
            ["steemd.database_api.get_state.params=['trending']", 30],
            ["steemd.database_api.get_state.params=['/hot']", 30],
            ["steemd.database_api.get_state.params=['/welcome']", 30],
            ["steemd.database_api.get_state.params=['/promoted']", 30],
            ["steemd.database_api.get_state.params=['/created']", 10],
            ["steemd.database_api.get_dynamic_global_properties", 1]
         ],
         "timeouts":[
            ["steemd", 5],
            ["steemd.network_broadcast_api", 0]
         ]
      },
      {
         "name":"appbase",
         "urls":[["appbase", "https://steemd.steemitdev.com"]],
         "ttls":[
            ["appbase", -2],
            ["appbase.block_api", -2],
            ["appbase.database_api", 1]
         ],
         "timeouts":[
            ["appbase", 3],
            ["appbase.chain_api.push_block", 0],
            ["appbase.chain_api.push_transaction", 0],
            ["appbase.network_broadcast_api", 0],
            ["appbase.condenser_api.broadcast_block", 0],
            ["appbase.condenser_api.broadcast_transaction", 0],
            ["appbase.condenser_api.broadcast_transaction_synchronous", 0]
         ]
      }
   ]
}

Upstreams can be added to the upstreams array:

{
  "name": "foo",
  "urls": [["foo", "https://foo.host.name"]],
  "ttls": [["foo", 3]],
  "timeouts": [["foo", 5]]
}

Once the above upstream is added to the local config and docker has been built, the following curl will work:

curl -s --data '{"jsonrpc":"2.0", "method":"foo.bar", "params":["baz"], "id":1}' http://localhost:9000

Benefits of jussi

Time To Live

Jussi can be configured with various TTL (Time To Live) schemes. A TTL is an integer value in seconds. Integers equal to or less than 0 have special meaning. A reasonable set of defaults would be:

Upstream API Method Parameters TTL (seconds)
steemd login_api all all -1
steemd network_broadcast_api all all -1
steemd follow_api all all 10
steemd market_history_api all all 1
steemd database_api all all 3
steemd database_api get_block all -2
steemd database_api get_block_header all -2
steemd database_api get_content all 1
steemd database_api get_state all 1
steemd database_api get_state '/trending' 30
steemd database_api get_state 'trending' 30
steemd database_api get_state '/hot' 30
steemd database_api get_state '/welcome' 30
steemd database_api get_state '/promoted' 30
steemd database_api get_state '/created' 10
steemd database_api get_dynamic_global_properties all 1
overseer all all all 5
conveyor all all all -1
sbds all all all 3
hivemind all all all 3
yo all all all 3

In this case, requests for login_api and network_broadcast_api have a TTL of -1, which means requests with those namespaces are not cached, whereas follow_api request have a TTL of 10 seconds.

Some methods and parameters have their own TTL that overrides the general default, like database_api.get_block, which overrides database_api.*.

Time to Live Special Meaning

If you have a local copy of jussi (see: Installation), you can change these defaults by modifying DEV_config.json.

json-rpc batch

Normally, a request is made with a JSON Object ({}). But jussi also supports batch requests, which is constructed with a JSON Array of Objects ([{}]).

For example, this would be a typical, non-batched JSON Object request that asks for a single block:

curl -s --data '{"jsonrpc":"2.0", "method":"condenser_api.get_block", "params":[1], "id":1}' https://api.steemit.com
{
   "id":1,
   "jsonrpc":"2.0",
   "result":{
      "previous":"0000000000000000000000000000000000000000",
      "timestamp":"2016-03-24T16:05:00",
      "witness":"initminer",
      "transaction_merkle_root":"0000000000000000000000000000000000000000",
      "extensions":[

      ],
      "witness_signature":"204f8ad56a8f5cf722a02b035a61b500aa59b9519b2c33c77a80c0a714680a5a5a7a340d909d19996613c5e4ae92146b9add8a7a663eef37d837ef881477313043",
      "transactions":[

      ],
      "block_id":"0000000109833ce528d5bbfb3f6225b39ee10086",
      "signing_key":"STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX",
      "transaction_ids":[

      ]
   }
}

To request more than one block using the batch construct, wrap each call in a JSON Array, that asks for two blocks in one request:

curl -s --data '[{"jsonrpc":"2.0", "method":"condenser_api.get_block", "params":[1], "id":1},{"jsonrpc":"2.0", "method":"condenser_api.get_block", "params":[2], "id":2}]' https://api.steemit.com
[
   {
      "id":1,
      "jsonrpc":"2.0",
      "result":{
         "previous":"0000000000000000000000000000000000000000",
         "timestamp":"2016-03-24T16:05:00",
         "witness":"initminer",
         "transaction_merkle_root":"0000000000000000000000000000000000000000",
         "extensions":[

         ],
         "witness_signature":"204f8ad56a8f5cf722a02b035a61b500aa59b9519b2c33c77a80c0a714680a5a5a7a340d909d19996613c5e4ae92146b9add8a7a663eef37d837ef881477313043",
         "transactions":[

         ],
         "block_id":"0000000109833ce528d5bbfb3f6225b39ee10086",
         "signing_key":"STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX",
         "transaction_ids":[

         ]
      }
   },
   {
      "id":2,
      "jsonrpc":"2.0",
      "result":{
         "previous":"0000000109833ce528d5bbfb3f6225b39ee10086",
         "timestamp":"2016-03-24T16:05:36",
         "witness":"initminer",
         "transaction_merkle_root":"0000000000000000000000000000000000000000",
         "extensions":[

         ],
         "witness_signature":"1f3e85ab301a600f391f11e859240f090a9404f8ebf0bf98df58eb17f455156e2d16e1dcfc621acb3a7acbedc86b6d2560fdd87ce5709e80fa333a2bbb92966df3",
         "transactions":[

         ],
         "block_id":"00000002ed04e3c3def0238f693931ee7eebbdf1",
         "signing_key":"STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX",
         "transaction_ids":[

         ]
      }
   }
]

Error responses are returned in the JSON Array response as well. Notice the "WRONG" parameter in the second element. The first block is returned as expected, the second one generates an error.

curl -s --data '[{"jsonrpc":"2.0", "method":"condenser_api.get_block", "params":[1], "id":1},{"jsonrpc":"2.0", "method":"condenser_api.get_block", "params":["WRONG"], "id":2}]' https://api.steemit.com
[
   {
      "jsonrpc":"2.0",
      "result":{
         "previous":"0000000000000000000000000000000000000000",
         "timestamp":"2016-03-24T16:05:00",
         "witness":"initminer",
         "transaction_merkle_root":"0000000000000000000000000000000000000000",
         "extensions":[

         ],
         "witness_signature":"204f8ad56a8f5cf722a02b035a61b500aa59b9519b2c33c77a80c0a714680a5a5a7a340d909d19996613c5e4ae92146b9add8a7a663eef37d837ef881477313043",
         "transactions":[

         ],
         "block_id":"0000000109833ce528d5bbfb3f6225b39ee10086",
         "signing_key":"STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX",
         "transaction_ids":[

         ]
      },
      "id":1
   },
   {
      "jsonrpc":"2.0",
      "error":{
         "code":-32000,
         "message":"Parse Error:Couldn't parse uint64_t",
         "data":{
            "code":4,
            "name":"parse_error_exception",
            "message":"Parse Error",
            "stack":[
               {
                  "context":{
                     "level":"error",
                     "file":"string.cpp",
                     "line":113,
                     "method":"to_uint64",
                     "hostname":"",
                     "timestamp":"2018-05-21T18:02:41"
                  },
                  "format":"Couldn't parse uint64_t",
                  "data":{

                  }
               },
               {
                  "context":{
                     "level":"warn",
                     "file":"string.cpp",
                     "line":116,
                     "method":"to_uint64",
                     "hostname":"",
                     "timestamp":"2018-05-21T18:02:41"
                  },
                  "format":"",
                  "data":{
                     "i":"WRONG"
                  }
               },
               {
                  "context":{
                     "level":"warn",
                     "file":"variant.cpp",
                     "line":405,
                     "method":"as_uint64",
                     "hostname":"",
                     "timestamp":"2018-05-21T18:02:41"
                  },
                  "format":"",
                  "data":{
                     "*this":"WRONG"
                  }
               }
            ]
         }
      },
      "id":2
   }
]

Footnotes


Latin

jussi

noun

declension: 2nd declension
gender: neuter

Definitions:
  1. order, command, decree, ordinance, law

SteemConnect

A Look at the Why’s and How’s of SteemConnect

Useful Links

Why SteemConnect was implemented

The goal of SteemConnect is to provide a safe way of connecting to the blockchain via 3rd party apps without compromising the security of your private keys and passwords. It’s a simple identity layer built on top of the blockchain allowing users safe access and developers the freedom of not having to handle the authentication system, i.e. managing users’ private keys and encryption. This means that devs won’t have to opensource their projects in order to gain user trust. When connecting to apps in this manner, neither SteemConnect nor the authorised app store the private keys as the posting key is incrypted on your cookie.

How SteemConnect is implemented

SteemConnect works by granting an access token to the requesting app once the application has been approved. A full tutorial on how to set up an application, request authorisation and grant access can be found HERE

Steem Authorisation and OAuth 2

The OAuth protocol allows third party apps to grant limited access to an HTTP service, either on behalf of a resource owner or by allowing the app to obtain access on its own behalf. The authorisation is provided without the private key or password of the user being shared with the third party. Simplified, the process includes the following steps:

  1. The user is presented with an authorisation link that requests a token from the API
  2. The user has to log in to the service to verify their identity whereupon they will be prompted to authorise the application
  3. The user is redirected to the application redirect URI along with the access token

Once the application has an access token, it may use the token to access the user’s account via the API, limited to the scope of access, until the token expires or is revoked. A full breakdown of OAuth2 and how it applies to SteemIt and SteemConnect can be found HERE

For additional material you can refer to the original steemit blog post by busy.org