github.com/decred/politeia@v1.4.0/politeiawww/api/www/v1/api.md (about)

     1  # politeiawww API Specification
     2  
     3  This document describes the REST API provided by a `politeiawww` server.  The
     4  `politeiawww` server is the web server backend and it interacts with a JSON
     5  REST API.  This document also describes websockets for server side
     6  notifications.  It does not render HTML.
     7  
     8  # v1
     9  
    10  **Methods**
    11  
    12  - [`Version`](#version)
    13  - [`Policy`](#policy)
    14  - [`New user`](#new-user)
    15  - [`Verify user`](#verify-user)
    16  - [`Resend verification`](#resend-verification)
    17  - [`Me`](#me)
    18  - [`Login`](#login)
    19  - [`Logout`](#logout)
    20  - [`User details`](#user-details)
    21  - [`Edit user`](#edit-user)
    22  - [`Manage user`](#manage-user)
    23  - [`Users`](#users)
    24  - [`Update user key`](#update-user-key)
    25  - [`Verify update user key`](#verify-update-user-key)
    26  - [`Change username`](#change-username)
    27  - [`Change password`](#change-password)
    28  - [`Reset password`](#reset-password)
    29  - [`User proposal credits`](#user-proposal-credits)
    30  - [`Proposal paywall details`](#proposal-paywall-details)
    31  - [`Verify user payment`](#verify-user-payment)
    32  - [`Rescan user payments`](#rescan-user-payments)
    33  
    34  **Proposal Routes**
    35  - [`Token inventory`](#token-inventory)
    36  - [`Proposal details`](#proposal-details)
    37  - [`Batch proposals`](#batch-proposals)
    38  - [`Vote results`](#vote-results)
    39  - [`Cast votes`](#cast-votes)
    40  - [`Batch vote summary`](#batch-vote-summary)
    41  
    42  
    43  **Error status codes**
    44  
    45  - [`ErrorStatusInvalid`](#ErrorStatusInvalid)
    46  - [`ErrorStatusInvalidPassword`](#ErrorStatusInvalidPassword)
    47  - [`ErrorStatusMalformedEmail`](#ErrorStatusMalformedEmail)
    48  - [`ErrorStatusVerificationTokenInvalid`](#ErrorStatusVerificationTokenInvalid)
    49  - [`ErrorStatusVerificationTokenExpired`](#ErrorStatusVerificationTokenExpired)
    50  - [`ErrorStatusProposalMissingFiles`](#ErrorStatusProposalMissingFiles)
    51  - [`ErrorStatusProposalNotFound`](#ErrorStatusProposalNotFound)
    52  - [`ErrorStatusProposalDuplicateFilenames`](#ErrorStatusProposalDuplicateFilenames)
    53  - [`ErrorStatusProposalInvalidTitle`](#ErrorStatusProposalInvalidTitle)
    54  - [`ErrorStatusMaxMDsExceededPolicy`](#ErrorStatusMaxMDsExceededPolicy)
    55  - [`ErrorStatusMaxImagesExceededPolicy`](#ErrorStatusMaxImagesExceededPolicy)
    56  - [`ErrorStatusMaxMDSizeExceededPolicy`](#ErrorStatusMaxMDSizeExceededPolicy)
    57  - [`ErrorStatusMaxImageSizeExceededPolicy`](#ErrorStatusMaxImageSizeExceededPolicy)
    58  - [`ErrorStatusMalformedPassword`](#ErrorStatusMalformedPassword)
    59  - [`ErrorStatusCommentNotFound`](#ErrorStatusCommentNotFound)
    60  - [`ErrorStatusInvalidFilename`](#ErrorStatusInvalidFilename)
    61  - [`ErrorStatusInvalidFileDigest`](#ErrorStatusInvalidFileDigest)
    62  - [`ErrorStatusInvalidBase64`](#ErrorStatusInvalidBase64)
    63  - [`ErrorStatusInvalidMIMEType`](#ErrorStatusInvalidMIMEType)
    64  - [`ErrorStatusUnsupportedMIMEType`](#ErrorStatusUnsupportedMIMEType)
    65  - [`ErrorStatusInvalidPropStatusTransition`](#ErrorStatusInvalidPropStatusTransition)
    66  - [`ErrorStatusInvalidPublicKey`](#ErrorStatusInvalidPublicKey)
    67  - [`ErrorStatusNoPublicKey`](#ErrorStatusNoPublicKey)
    68  - [`ErrorStatusInvalidSignature`](#ErrorStatusInvalidSignature)
    69  - [`ErrorStatusInvalidInput`](#ErrorStatusInvalidInput)
    70  - [`ErrorStatusInvalidSigningKey`](#ErrorStatusInvalidSigningKey)
    71  - [`ErrorStatusCommentLengthExceededPolicy`](#ErrorStatusCommentLengthExceededPolicy)
    72  - [`ErrorStatusUserNotFound`](#ErrorStatusUserNotFound)
    73  - [`ErrorStatusWrongStatus`](#ErrorStatusWrongStatus)
    74  - [`ErrorStatusNotLoggedIn`](#ErrorStatusNotLoggedIn)
    75  - [`ErrorStatusUserNotPaid`](#ErrorStatusUserNotPaid)
    76  - [`ErrorStatusReviewerAdminEqualsAuthor`](#ErrorStatusReviewerAdminEqualsAuthor)
    77  - [`ErrorStatusMalformedUsername`](#ErrorStatusMalformedUsername)
    78  - [`ErrorStatusDuplicateUsername`](#ErrorStatusDuplicateUsername)
    79  - [`ErrorStatusVerificationTokenUnexpired`](#ErrorStatusVerificationTokenUnexpired)
    80  - [`ErrorStatusCannotVerifyPayment`](#ErrorStatusCannotVerifyPayment)
    81  - [`ErrorStatusDuplicatePublicKey`](#ErrorStatusDuplicatePublicKey)
    82  - [`ErrorStatusInvalidPropVoteStatus`](#ErrorStatusInvalidPropVoteStatus)
    83  - [`ErrorStatusNoProposalCredits`](#ErrorStatusNoProposalCredits)
    84  - [`ErrorStatusInvalidUserManageAction`](#ErrorStatusInvalidUserManageAction)
    85  - [`ErrorStatusUserActionNotAllowed`](#ErrorStatusUserActionNotAllowed)
    86  - [`ErrorStatusWrongVoteStatus`](#ErrorStatusWrongVoteStatus)
    87  - [`ErrorStatusCannotVoteOnPropComment`](#ErrorStatusCannotVoteOnPropComment)
    88  - [`ErrorStatusChangeMessageCannotBeBlank`](#ErrorStatusChangeMessageCannotBeBlank)
    89  - [`ErrorStatusCensorReasonCannotBeBlank`](#ErrorStatusCensorReasonCannotBeBlank)
    90  - [`ErrorStatusCannotCensorComment`](#ErrorStatusCannotCensorComment)
    91  - [`ErrorStatusUserNotAuthor`](#ErrorStatusUserNotAuthor)
    92  - [`ErrorStatusVoteNotAuthorized`](#ErrorStatusVoteNotAuthorized)
    93  - [`ErrorStatusVoteAlreadyAuthorized`](#ErrorStatusVoteAlreadyAuthorized)
    94  - [`ErrorStatusInvalidAuthVoteAction`](#ErrorStatusInvalidAuthVoteAction)
    95  - [`ErrorStatusUserDeactivated`](#ErrorStatusUserDeactivated)
    96  - [`ErrorStatusInvalidPropVoteBits`](#ErrorStatusInvalidPropVoteBits)
    97  - [`ErrorStatusInvalidPropVoteParams`](#ErrorStatusInvalidPropVoteParams)
    98  - [`ErrorStatusEmailNotVerified`](#ErrorStatusEmailNotVerified)
    99  - [`ErrorStatusInvalidUUID`](#ErrorStatusInvalidUUID)
   100  - [`ErrorStatusInvalidLikeCommentAction`](#ErrorStatusInvalidLikeCommentAction)
   101  - [`ErrorStatusInvalidCensorshipToken`](#ErrorStatusInvalidCensorshipToken)
   102  - [`ErrorStatusEmailAlreadyVerified`](#ErrorStatusEmailAlreadyVerified)
   103  - [`ErrorStatusNoProposalChanges`](#ErrorStatusNoProposalChanges)
   104  - [`ErrorStatusMaxProposalsExceededPolicy`](#ErrorStatusMaxProposalsExceededPolicy)
   105  - [`ErrorStatusDuplicateComment`](#ErrorStatusDuplicateComment)
   106  - [`ErrorStatusInvalidLogin`](#ErrorStatusInvalidLogin)
   107  - [`ErrorStatusCommentIsCensored`](#ErrorStatusCommentIsCensored)
   108  - [`ErrorStatusInvalidProposalVersion`](#ErrorStatusInvalidProposalVersion)
   109  - [`ErrorStatusMetadataInvalid`](#ErrorStatusMetadataInvalid)
   110  - [`ErrorStatusMetadataMissing`](#ErrorStatusMetadataMissing)
   111  - [`ErrorStatusMetadataDigestInvalid`](#ErrorStatusMetadataDigestInvalid)
   112  - [`ErrorStatusInvalidVoteType`](#ErrorStatusInvalidVoteType)
   113  - [`ErrorStatusInvalidVoteOptions`](#ErrorStatusInvalidVoteOptions)
   114  - [`ErrorStatusLinkByDeadlineNotMet`](#ErrorStatusLinkByDeadlineNotMet)
   115  - [`ErrorStatusNoLinkedProposals`](#ErrorStatusNoLinkedProposals)
   116  - [`ErrorStatusInvalidLinkTo`](#ErrorStatusInvalidLinkTo)
   117  - [`ErrorStatusInvalidLinkBy`](#ErrorStatusInvalidLinkBy)
   118  - [`ErrorStatusInvalidRunoffVote`](#ErrorStatusInvalidRunoffVote)
   119  - [`ErrorStatusWrongProposalType`](#ErrorStatusWrongProposalType)
   120  
   121  **Websockets**
   122  
   123  See [`Websocket command flow`](#Websocket-command-flow) for a generic
   124  description of websocket command flow.
   125  
   126  - [`WSError`](#WSError)
   127  - [`WSHeader`](#WSHeader)
   128  - [`WSPing`](#WSPing)
   129  - [`WSSubscribe`](#WSSubscribe)
   130  
   131  ## HTTP status codes and errors
   132  
   133  All methods, unless otherwise specified, shall return `200 OK` when successful,
   134  `400 Bad Request` when an error has occurred due to user input, or `500
   135  Internal Server Error` when an unexpected server error has occurred. The format
   136  of errors is as follows:
   137  
   138  **`4xx` errors**
   139  
   140  | | Type | Description |
   141  |-|-|-|
   142  | errorcode | number | One of the [error codes](#error-codes) |
   143  | errorcontext | Array of Strings | This array of strings is used to provide additional information for certain errors; see the documentation for specific error codes. |
   144  
   145  **`5xx` errors**
   146  
   147  | | Type | Description |
   148  |-|-|-|
   149  | errorcode | number | An error code that can be used to track down the internal server error that occurred; it should be reported to Politeia administrators. |
   150  
   151  ## Websocket command flow
   152  
   153  There are two distinct websockets routes. There is an unauthenticated route and
   154  an authenticated route.  The authenticated route provides access to all
   155  unprivileged websocket commands and therefore a client that authenticates
   156  itself via the [`Login`](#login) call should close any open unprivileged
   157  websockets.  Note that sending notifications to unauthenticated users means
   158  **ALL** unauthenticated users; this may be expensive and should be used
   159  carefully.
   160  
   161  All commands consist of two JSON structures. All commands are prefixed by a
   162  [`WSHeader`](#WSHeader) structure that identifies the command that follows.
   163  This is done to prevent decoding JSON multiple times.  That structure also
   164  contains a convenience field called **ID** which can be set by the client in
   165  order to identify prior sent commands.
   166  
   167  If a client command fails the server shall return a [`WSError`](#WSError)
   168  structure, prefixed by a [`WSHeader`](#WSHeader) structure that contains the
   169  client side **ID** followed by the error(s) itself.  If there is no failure the
   170  server does not reply.  Note that **ID** is unused when server notifications
   171  flow to the client.
   172  
   173  Both routes operate exactly the same way. The only difference is denied access
   174  to subscriptions of privileged notifications.
   175  
   176  **Unauthenticated route**: `/v1/ws`
   177  **Authenticated route**: `/v1/aws`
   178  
   179  For example, a subscribe command consists of a [`WSHeader`](#WSHeader)
   180  structure followed by a [`WSSubscribe`](#WSSubscribe) structure:
   181  ```
   182  {
   183    "command": "subscribe",
   184    "id": "1"
   185  }
   186  {
   187    "rpcs": [
   188      "ping"
   189    ]
   190  }
   191  ```
   192  
   193  The same example but with an invalid subscription:
   194  ```
   195  {
   196    "command": "subscribe",
   197    "id": "1"
   198  }
   199  {
   200    "rpcs": [
   201      "pingo"
   202    ]
   203  }
   204  ```
   205  
   206  Since **pingo** is an invalid subscription the server will reply with the
   207  following error:
   208  ```
   209  {
   210    "command": "error",
   211    "id": "1"
   212  }
   213  {
   214    "command": "subscribe",
   215    "id": "1",
   216    "errors": [
   217      "invalid subscription pingo"
   218    ]
   219  }
   220  ```
   221  
   222  ## Methods
   223  
   224  ### `Version`
   225  
   226  Obtain version, route information and signing identity from server.  This call
   227  shall **ALWAYS** be the first contact with the server.  This is done in order
   228  to get the CSRF token for the session and to ensure API compatibility.
   229  
   230  **Route**: `GET /` and `GET /version`
   231  
   232  **Params**: none
   233  
   234  **Results**:
   235  
   236  | | Type | Description |
   237  |-|-|-|
   238  | version | number | API version that is running on this server. |
   239  | route | string | Route that should be prepended to all calls. For example, "/v1". |
   240  | pubkey | string | The public key for the corresponding private key that signs various tokens to ensure server authenticity and to prevent replay attacks. |
   241  | testnet | boolean | Value to inform either its running on testnet or not |
   242  | mode | string | Current mode that politeiawww is running (possibly piwww or cmswww) |
   243  | activeusersesstion | boolean | Indicates if there is an active user from the session or not |
   244  
   245  **Example**
   246  
   247  Request:
   248  
   249  ```json
   250  {}
   251  ```
   252  
   253  Reply:
   254  
   255  ```json
   256  {
   257    "version": 1,
   258    "route": "/v1",
   259    "pubkey": "99e748e13d7ecf70ef6b5afa376d692cd7cb4dbb3d26fa83f417d29e44c6bb6c",
   260    "testnet": true,
   261    "mode": "piwww",
   262    "activeusersession": true
   263  }
   264  ```
   265  
   266  ### `Me`
   267  
   268  Return pertinent user information of the current logged in user.
   269  
   270  **Route**: `GET /v1/user/me`
   271  
   272  **Params**: none
   273  
   274  **Results**: See the [`Login reply`](#login-reply).
   275  
   276  **Example**
   277  
   278  Request:
   279  
   280  ```json
   281  {}
   282  ```
   283  
   284  Reply:
   285  
   286  ```json
   287  {
   288    "isadmin":false,
   289    "userid":"12",
   290    "email":"69af376cca42cd9c@example.com",
   291    "publickey":"5203ab0bb739f3fc267ad20c945b81bcb68ff22414510c000305f4f0afb90d1b",
   292    "paywalladdress":"Tsgs7qb1Gnc43D9EY3xx9ou8Lbo8rB7me6M",
   293    "paywallamount": 10000000,
   294    "paywalltxnotbefore": 1528821554
   295  }
   296  ```
   297  
   298  ### `New user`
   299  
   300  Create a new user on the politeiawww server.
   301  
   302  **Route:** `POST /v1/user/new`
   303  
   304  **Params:**
   305  
   306  | Parameter | Type | Description | Required |
   307  |-|-|-|-|
   308  | email | string | Email is used as the web site user identity for a user. When a user changes email addresses the server shall maintain a mapping between the old and new address. | Yes |
   309  | username | string | Unique username that the user wishes to use. | Yes |
   310  | password | string | The password that the user wishes to use. This password travels in the clear in order to enable JS-less systems. The server shall never store passwords in the clear. | Yes |
   311  | publickey | string | User ed25519 public key. | Yes |
   312  
   313  **Results:**
   314  
   315  | Parameter | Type | Description |
   316  |-|-|-|
   317  | verificationtoken | String | The verification token which is required when calling [`Verify user`](#verify-user). If an email server is set up, this property will be empty or nonexistent; the token will be sent to the email address sent in the request.|
   318  
   319  This call can return one of the following error codes:
   320  
   321  - [`ErrorStatusMalformedEmail`](#ErrorStatusMalformedEmail)
   322  - [`ErrorStatusMalformedUsername`](#ErrorStatusMalformedUsername)
   323  - [`ErrorStatusDuplicateUsername`](#ErrorStatusDuplicateUsername)
   324  - [`ErrorStatusMalformedPassword`](#ErrorStatusMalformedPassword)
   325  - [`ErrorStatusInvalidPublicKey`](#ErrorStatusInvalidPublicKey)
   326  - [`ErrorStatusDuplicatePublicKey`](#ErrorStatusDuplicatePublicKey)
   327  
   328  The email shall include a link in the following format:
   329  
   330  ```
   331  /user/verify?email=69af376cca42cd9c@example.com&verificationtoken=fc8f660e7f4d590e27e6b11639ceeaaec2ce9bc6b0303344555ac023ab8ee55f
   332  ```
   333  
   334  The call may return `500 Internal Server Error` which is accompanied by
   335  an error code that allows the server operator to correlate issues with user
   336  reports.
   337  
   338  * **Example**
   339  
   340  Request:
   341  
   342  ```json
   343  {
   344    "email": "69af376cca42cd9c@example.com",
   345    "password": "69af376cca42cd9c",
   346    "username": "foobar",
   347    "publickey":"5203ab0bb739f3fc267ad20c945b81bcb68ff22414510c000305f4f0afb90d1b"
   348  }
   349  ```
   350  
   351  Reply:
   352  
   353  ```json
   354  {
   355    "verificationtoken": "fc8f660e7f4d590e27e6b11639ceeaaec2ce9bc6b0303344555ac023ab8ee55f"
   356  }
   357  ```
   358  
   359  ### `Verify user`
   360  
   361  Verify email address of a previously created user.
   362  
   363  **Route:** `GET /v1/user/verify`
   364  
   365  **Params:**
   366  
   367  | Parameter | Type | Description | Required |
   368  |-|-|-|-|
   369  | email | string | Email address of previously created user. | Yes |
   370  | verificationtoken | string | The token that was provided by email to the user. | Yes |
   371  | signature | string | The ed25519 signature of the string representation of the verification token. | Yes |
   372  
   373  **Results:** none
   374  
   375  On success the call shall return `200 OK`.
   376  
   377  On failure the call shall return `400 Bad Request` and one of the following error codes:
   378  - [`ErrorStatusVerificationTokenInvalid`](#ErrorStatusVerificationTokenInvalid)
   379  - [`ErrorStatusVerificationTokenExpired`](#ErrorStatusVerificationTokenExpired)
   380  - [`ErrorStatusNoPublicKey`](#ErrorStatusNoPublicKey)
   381  - [`ErrorStatusInvalidPublicKey`](#ErrorStatusInvalidPublicKey)
   382  - [`ErrorStatusInvalidSignature`](#ErrorStatusInvalidSignature)
   383  - [`ErrorStatusInvalidInput`](#ErrorStatusInvalidInput)
   384  
   385  **Example:**
   386  
   387  Request:
   388  
   389  The request params should be provided within the URL:
   390  
   391  ```
   392  /v1/user/verify?email=abc@example.com&verificationtoken=f1c2042d36c8603517cf24768b6475e18745943e4c6a20bc0001f52a2a6f9bde&signature=9e4b1018913610c12496ec3e482f2fb42129197001c5d35d4f5848b77d2b5e5071f79b18bcab4f371c5b378280bb478c153b696003ac3a627c3d8a088cd5f00d
   393  ```
   394  
   395  Reply:
   396  
   397  ```json
   398  {}
   399  ```
   400  
   401  ### `Resend verification`
   402  
   403  Sends another verification email for a new user registration.
   404  
   405  **Route:** `POST /v1/user/new/resend`
   406  
   407  **Params:**
   408  
   409  | Parameter | Type | Description | Required |
   410  |-|-|-|-|
   411  | email | string | Email address which was used to sign up. | Yes |
   412  | publickey | string | User ed25519 public key. This can be the same key used to sign up or a new one. | Yes |
   413  
   414  **Results:**
   415  
   416  | Parameter | Type | Description |
   417  |-|-|-|
   418  | verificationtoken | String | The verification token which is required when calling [`Verify user`](#verify-user). If an email server is set up, this property will be empty or nonexistent; the token will be sent to the email address sent in the request.|
   419  
   420  This call can return one of the following error codes:
   421  
   422  - [`ErrorStatusInvalidPublicKey`](#ErrorStatusInvalidPublicKey)
   423  - [`ErrorStatusDuplicatePublicKey`](#ErrorStatusDuplicatePublicKey)
   424  
   425  The email shall include a link in the following format:
   426  
   427  ```
   428  /user/verify?email=69af376cca42cd9c@example.com&verificationtoken=fc8f660e7f4d590e27e6b11639ceeaaec2ce9bc6b0303344555ac023ab8ee55f
   429  ```
   430  
   431  The call may return `500 Internal Server Error` which is accompanied by
   432  an error code that allows the server operator to correlate issues with user
   433  reports.
   434  
   435  * **Example**
   436  
   437  Request:
   438  
   439  ```json
   440  {
   441    "email": "69af376cca42cd9c@example.com",
   442    "publickey":"5203ab0bb739f3fc267ad20c945b81bcb68ff22414510c000305f4f0afb90d1b"
   443  }
   444  ```
   445  
   446  Reply:
   447  
   448  ```json
   449  {
   450    "verificationtoken": "fc8f660e7f4d590e27e6b11639ceeaaec2ce9bc6b0303344555ac023ab8ee55f"
   451  }
   452  ```
   453  
   454  ### `Login`
   455  
   456  Login as a user or admin.  Admin status is determined by the server based on
   457  the user database.  Note that Login reply is identical to Me reply.
   458  
   459  A valid TOTP code is required if user has set and verified a TOTP secret 
   460  key previously.
   461  
   462  **Route:** `POST /v1/login`
   463  
   464  **Params:**
   465  
   466  | Parameter | Type | Description | Required |
   467  |-|-|-|-|
   468  | email | string | Email address of user that is attempting to login. | Yes |
   469  | password | string | Accompanying password for provided email. | Yes |
   470  | code | string | TOTP code based on user's TOTP secret (if verified). | No |
   471  
   472  **Results:** See the [`Login reply`](#login-reply).
   473  
   474  On failure the call shall return `401 Unauthorized` and one of the following
   475  error codes:
   476  - [`ErrorStatusInvalidLogin`](#ErrorStatusInvalidLogin)
   477  - [`ErrorStatusEmailNotVerified`](#ErrorStatusEmailNotVerified)
   478  - [`ErrorStatusUserDeactivated`](#ErrorStatusUserDeactivated)
   479  - [`ErrorStatusUserLocked`](#ErrorStatusUserLocked)
   480  - [`ErrorStatusRequiresTOTPCode`](#ErrorStatusRequiresTOTPCode)
   481  - [`ErrorStatusTOTPWaitForNewCode`](#ErrorStatusTOTPWaitForNewCode)
   482  - [`ErrorStatusTOTPFailedValidation`](#ErrorStatusTOTPFailedValidation)
   483  
   484  **Example**
   485  
   486  Request:
   487  
   488  ```json
   489  {
   490    "email":"26c5687daca2f5d8@example.com",
   491    "password":"26c5687daca2f5d8"
   492  }
   493  ```
   494  
   495  Reply:
   496  
   497  ```json
   498  {
   499    "isadmin":true,
   500    "userid":"0",
   501    "email":"26c5687daca2f5d8@example.com",
   502    "publickey":"ec88b934fd9f334a9ed6d2e719da2bdb2061de5370ff20a38b0e1e3c9538199a",
   503    "paywalladdress":"",
   504    "paywallamount":"",
   505    "paywalltxnotbefore":""
   506  }
   507  ```
   508  
   509  ### `Logout`
   510  
   511  Logout as a user or admin.
   512  
   513  **Route:** `POST /v1/logout`
   514  
   515  **Params:** none
   516  
   517  **Results:** none
   518  
   519  **Example**
   520  
   521  Request:
   522  
   523  ```json
   524  {}
   525  ```
   526  
   527  Reply:
   528  
   529  ```json
   530  {}
   531  ```
   532  
   533  ### `Verify user payment`
   534  
   535  Checks that a user has paid his user registration fee.
   536  
   537  **Route:** `GET /v1/user/payments/registration`
   538  
   539  **Params:** none
   540  
   541  **Results:**
   542  
   543  | Parameter | Type | Description |
   544  |-|-|-|
   545  | haspaid | boolean | Whether or not a transaction on the blockchain that was sent to the `paywalladdress` |
   546  | paywalladdress | String | The address in which to send the transaction containing the `paywallamount`.  If the user has already paid, this field will be empty or not present. |
   547  | paywallamount | Int64 | The amount of DCR (in atoms) to send to `paywalladdress`.  If the user has already paid, this field will be empty or not present. |
   548  | paywalltxnotbefore | Int64 | The minimum UNIX time (in seconds) required for the block containing the transaction sent to `paywalladdress`.  If the user has already paid, this field will be empty or not present. |
   549  
   550  On failure the call shall return `400 Bad Request` and one of the following
   551  error codes:
   552  - [`ErrorStatusCannotVerifyPayment`](#ErrorStatusCannotVerifyPayment)
   553  
   554  **Example**
   555  
   556  Request:
   557  
   558  ```
   559  /v1/user/payments/registration
   560  ```
   561  
   562  Reply:
   563  
   564  ```json
   565  {
   566    "haspaid": true,
   567    "paywalladdress":"",
   568    "paywallamount":"",
   569    "paywalltxnotbefore":""
   570  }
   571  ```
   572  
   573  ### `Rescan user payments`
   574  
   575  Rescan payments made by the user.
   576  
   577  **Route:** `GET /v1/user/payments/rescan`
   578  
   579  **Params:**
   580  | Parameter | Type | Description | Required |
   581  |-----------|------|-------------|----------|
   582  | userid | string | The unique id of the user. | Yes |
   583  
   584  **Results:**
   585  
   586  | Parameter | Type | Description |
   587  |-|-|-|
   588  | newcredits | []ProposalCredits | Contains information about the user's
   589  proposal credits payments` |
   590  
   591  On failure the call shall return `400 Bad Request` and one of the following
   592  error codes:
   593  - [`ErrorStatusInvalidInput`](#ErrorStatusInvalidInput)
   594  
   595  **Example**
   596  
   597  Request:
   598  
   599  ```
   600  /v1/user/payments/rescan
   601  ```
   602  Request:
   603  
   604  ```json
   605  {
   606    "userid": "1"
   607  }
   608  ```
   609  
   610  Reply:
   611  
   612  ```json
   613  {
   614    "newcredits": [
   615      {
   616        "paywallid": 1,
   617        "price": 10000000,
   618        "datepurchased": 1528821554,
   619        "txid": "ff0207a03b761cb409c7677c5b5521562302653d2236c92d016dd47e0ae37bf7",
   620      },
   621    ]
   622  }
   623  ```
   624  
   625  ### `User details`
   626  
   627  Returns details about a user given its id. Returns complete data if request is from
   628  admin or own user, and omits private data if request is from a normal user or logged
   629  out user.
   630  
   631  **Route:** `GET /v1/user/{userid}`
   632  
   633  **Params:**
   634  
   635  | Parameter | Type | Description | Required |
   636  |-----------|------|-------------|----------|
   637  | userid | string | The unique id of the user. | Yes |
   638  
   639  **Results:**
   640  
   641  | Parameter | Type | Description |
   642  |-|-|-|
   643  | user | [User](#user) | The user details. |
   644  
   645  On failure the call shall return `400 Bad Request` and one of the following
   646  error codes:
   647  - [`ErrorStatusUserNotFound`](#ErrorStatusUserNotFound)
   648  
   649  **Example**
   650  
   651  Request:
   652  
   653  ```json
   654  {
   655    "userid": "0"
   656  }
   657  ```
   658  
   659  Reply:
   660  
   661  For a logged in admin user or own user requesting data.
   662  
   663  ```json
   664  {
   665    "user": {
   666      "id": "0",
   667      "email": "6b87b6ebb0c80cb7@example.com",
   668      "username": "6b87b6ebb0c80cb7",
   669      "isadmin": false,
   670      "newuserpaywalladdress": "Tsgs7qb1Gnc43D9EY3xx9ou8Lbo8rB7me6M",
   671      "newuserpaywallamount": 10000000,
   672      "newuserpaywalltx": "",
   673      "newuserpaywalltxnotbefore": 1528821554,
   674      "newuserpaywallpollexpiry": 1528821554,
   675      "newuserverificationtoken":
   676        "337fc4762dac6bbe11d3d0130f33a09978004b190e6ebbbde9312ac63f223527",
   677      "newuserverificationexpiry": 1528821554,
   678      "updatekeyverificationtoken":
   679        "337fc4762dac6bbe11d3d0130f33a09978004b190e6ebbbde9312ac63f223527",
   680      "updatekeyverificationexpiry": 1528821554,
   681      "resetpasswordverificationtoken":
   682        "337fc4762dac6bbe11d3d0130f33a09978004b190e6ebbbde9312ac63f223527",
   683      "resetpasswordverificationexpiry": 1528821554,
   684      "lastlogintime": 1571316271,
   685      "failedloginattemps": 3,
   686      "isdeactivated": false,
   687      "islocked": false,
   688      "identities": [{
   689        "pubkey":
   690          "5203ab0bb739f3fc267ad20c945b81bcb68ff22414510c000305f4f0afb90d1b",
   691        "isactive": true
   692      }],
   693      "proposalCredits": 10,
   694      "emailnotifications": 3
   695    }
   696  }
   697  ```
   698  
   699  Reply:
   700  
   701  For a unlogged or normal user requesting data.
   702  
   703  ```json
   704  {
   705    "user": {
   706      "id": "0",
   707      "email": "",
   708      "username": "6b87b6ebb0c80cb7",
   709      "isadmin": false,
   710      "newuserpaywalladdress": "",
   711      "newuserpaywallamount": 0,
   712      "newuserpaywalltx": "",
   713      "newuserpaywalltxnotbefore": 0,
   714      "newuserpaywallpollexpiry": 0,
   715      "newuserverificationtoken": "",
   716      "newuserverificationexpiry": 0,
   717      "updatekeyverificationtoken": null,
   718      "updatekeyverificationexpiry": 0,
   719      "resetpasswordverificationtoken": null,
   720      "resetpasswordverificationexpiry": 0,
   721      "lastlogintime": 0,
   722      "failedloginattemps": 0,
   723      "isdeactivated": false,
   724      "islocked": false,
   725      "identities": [{
   726        "pubkey":
   727          "5203ab0bb739f3fc267ad20c945b81bcb68ff22414510c000305f4f0afb90d1b",
   728        "isactive": true
   729      }],
   730      "proposalCredits": 0,
   731      "emailnotifications": 0
   732    }
   733  }
   734  ```
   735  ### `Edit user`
   736  
   737  Edits a user's details. This call requires login privileges.
   738  
   739  **Route:** `POST /v1/user/edit`
   740  
   741  **Params:**
   742  
   743  | Parameter | Type | Description | Required |
   744  |-----------|------|-------------|----------|
   745  | emailnotifications | uint64 | The unique id of the user. | Yes |
   746  
   747  **Results:** none
   748  
   749  On failure the call shall return `400 Bad Request` and one of the following
   750  error codes:
   751  - [`ErrorStatusInvalidInput`](#ErrorStatusInvalidInput)
   752  
   753  **Example**
   754  
   755  Request:
   756  
   757  ```json
   758  {
   759    "emailnotifications": 2,
   760  }
   761  ```
   762  
   763  Reply:
   764  
   765  ```json
   766  {}
   767  ```
   768  
   769  ### `Manage user`
   770  
   771  Edits a user's details. This call requires admin privileges.
   772  
   773  **Route:** `POST /v1/user/manage`
   774  
   775  **Params:**
   776  
   777  | Parameter | Type | Description | Required |
   778  |-----------|------|-------------|----------|
   779  | userid | string | The unique id of the user. | Yes |
   780  | action | int64 | The [user edit action](#user-edit-actions) to execute on the user. | Yes |
   781  | reason | string | The admin's reason for executing this action. | Yes |
   782  
   783  **Results:** none
   784  
   785  On failure the call shall return `400 Bad Request` and one of the following
   786  error codes:
   787  - [`ErrorStatusUserNotFound`](#ErrorStatusUserNotFound)
   788  - [`ErrorStatusInvalidInput`](#ErrorStatusInvalidInput)
   789  - [`ErrorStatusInvalidUserManageAction`](#ErrorStatusInvalidUserManageAction)
   790  
   791  **Example**
   792  
   793  Request:
   794  
   795  ```json
   796  {
   797    "userid": "0",
   798    "action": 1
   799  }
   800  ```
   801  
   802  Reply:
   803  
   804  ```json
   805  {}
   806  ```
   807  
   808  ### `Users`
   809  
   810  Returns a list of users given optional filters. This call requires admin privileges.
   811  
   812  **Route:** `GET /v1/users`
   813  
   814  **Params:**
   815  
   816  | Parameter | Type | Description | Required |
   817  |-----------|------|-------------|----------|
   818  | email | string | A query string to match against user email addresses. | |
   819  | username | string | A query string to match against usernames. | |
   820  
   821  **Results:**
   822  
   823  | Parameter | Type | Description |
   824  |-|-|-|
   825  | totalusers | uint64 | The total number of all users in the database. |
   826  | totalmatches | uint64 | The total number of users that matched the query. |
   827  | users | array of [Abridged User](#abridged-user) | The list of users that match the query. This list will be capped at the `userlistpagesize`, which is specified in the [`Policy`](#policy) call. |
   828  
   829  On failure the call shall return `400 Bad Request` and one of the following
   830  error codes:
   831  - [`ErrorStatusInvalidInput`](#ErrorStatusInvalidInput)
   832  
   833  **Example**
   834  
   835  Request:
   836  
   837  ```json
   838  {
   839    "email": "@aol.com",
   840    "username": "JakeFromStateFarm"
   841  }
   842  ```
   843  
   844  Reply:
   845  
   846  ```json
   847  {
   848    "totalusers": 132,
   849    "totalmatches": 0,
   850    "users": []
   851  }
   852  ```
   853  
   854  ### `Update user key`
   855  
   856  Updates the user's active key pair.
   857  
   858  **Route:** `POST /v1/user/key`
   859  
   860  **Params:**
   861  
   862  | Parameter | Type | Description | Required |
   863  |-|-|-|-|
   864  | publickey | string | User's new active ed25519 public key. | Yes |
   865  
   866  **Results:**
   867  
   868  | Parameter | Type | Description |
   869  |-|-|-|
   870  | verificationtoken | String | The verification token which is required when calling [`Verify update user key`](#verify-update-user-key). If an email server is set up, this property will be empty or nonexistent; the token will be sent to the email address sent in the request. |
   871  
   872  This call can return one of the following error codes:
   873  
   874  - [`ErrorStatusInvalidPublicKey`](#ErrorStatusInvalidPublicKey)
   875  - [`ErrorStatusVerificationTokenUnexpired`](#ErrorStatusVerificationTokenUnexpired)
   876  
   877  The email shall include a link in the following format:
   878  
   879  ```
   880  /v1/user/key/verify?verificationtoken=fc8f660e7f4d590e27e6b11639ceeaaec2ce9bc6b0303344555ac023ab8ee55
   881  ```
   882  
   883  The call may return `500 Internal Server Error` which is accompanied by
   884  an error code that allows the server operator to correlate issues with user
   885  reports.
   886  
   887  * **Example**
   888  
   889  Request:
   890  
   891  ```json
   892  {
   893    "publickey":"5203ab0bb739f3fc267ad20c945b81bcb68ff22414510c000305f4f0afb90d1b"
   894  }
   895  ```
   896  
   897  Reply:
   898  
   899  ```json
   900  {
   901    "verificationtoken": "fc8f660e7f4d590e27e6b11639ceeaaec2ce9bc6b0303344555ac023ab8ee55f"
   902  }
   903  ```
   904  
   905  ### `Verify update user key`
   906  
   907  Verify the new key pair for the user.
   908  
   909  **Route:** `POST /v1/user/key/verify`
   910  
   911  **Params:**
   912  
   913  | Parameter | Type | Description | Required |
   914  |-|-|-|-|
   915  | verificationtoken | string | The token that was provided by email to the user. | Yes |
   916  | signature | string | The ed25519 signature of the string representation of the verification token. | Yes |
   917  
   918  **Results:** none
   919  
   920  On success the call shall return `200 OK`.
   921  
   922  On failure the call shall return `400 Bad Request` and one of the following error codes:
   923  - [`ErrorStatusVerificationTokenInvalid`](#ErrorStatusVerificationTokenInvalid)
   924  - [`ErrorStatusVerificationTokenExpired`](#ErrorStatusVerificationTokenExpired)
   925  - [`ErrorStatusNoPublicKey`](#ErrorStatusNoPublicKey)
   926  - [`ErrorStatusInvalidPublicKey`](#ErrorStatusInvalidPublicKey)
   927  - [`ErrorStatusInvalidSignature`](#ErrorStatusInvalidSignature)
   928  - [`ErrorStatusInvalidInput`](#ErrorStatusInvalidInput)
   929  
   930  **Example:**
   931  
   932  Request:
   933  
   934  The request params should be provided within the URL:
   935  
   936  ```json
   937  {
   938    "verificationtoken":"f1c2042d36c8603517cf24768b6475e18745943e4c6a20bc0001f52a2a6f9bde",
   939    "signature":"9e4b1018913610c12496ec3e482f2fb42129197001c5d35d4f5848b77d2b5e5071f79b18bcab4f371c5b378280bb478c153b696003ac3a627c3d8a088cd5f00d"
   940  }
   941  ```
   942  
   943  Reply:
   944  
   945  ```json
   946  {}
   947  ```
   948  
   949  ### `Change username`
   950  
   951  Changes the username for the currently logged in user.
   952  
   953  **Route:** `POST /v1/user/username/change`
   954  
   955  **Params:**
   956  
   957  | Parameter | Type | Description | Required |
   958  |-|-|-|-|
   959  | password | string | The current password of the logged in user. | Yes |
   960  | newusername | string | The new username for the logged in user. | Yes |
   961  
   962  **Results:** none
   963  
   964  On failure the call shall return `400 Bad Request` and one of the following
   965  error codes:
   966  - [`ErrorStatusInvalidPassword`](#ErrorStatusInvalidPassword)
   967  - [`ErrorStatusMalformedUsername`](#ErrorStatusMalformedUsername)
   968  - [`ErrorStatusDuplicateUsername`](#ErrorStatusDuplicateUsername)
   969  
   970  **Example**
   971  
   972  Request:
   973  
   974  ```json
   975  {
   976    "password": "15a1eb6de3681fec",
   977    "newusername": "foobar"
   978  }
   979  ```
   980  
   981  Reply:
   982  
   983  ```json
   984  {}
   985  ```
   986  
   987  ### `Change password`
   988  
   989  Changes the password for the currently logged in user.
   990  
   991  **Route:** `POST /v1/user/password/change`
   992  
   993  **Params:**
   994  
   995  | Parameter | Type | Description | Required |
   996  |-|-|-|-|
   997  | currentpassword | string | The current password of the logged in user. | Yes |
   998  | newpassword | string | The new password for the logged in user. | Yes |
   999  
  1000  **Results:** none
  1001  
  1002  On failure the call shall return `400 Bad Request` and one of the following
  1003  error codes:
  1004  - [`ErrorStatusInvalidPassword`](#ErrorStatusInvalidPassword)
  1005  - [`ErrorStatusMalformedPassword`](#ErrorStatusMalformedPassword)
  1006  
  1007  **Example**
  1008  
  1009  Request:
  1010  
  1011  ```json
  1012  {
  1013    "currentpassword": "15a1eb6de3681fec",
  1014    "newpassword": "cef1863ed6be1a51"
  1015  }
  1016  ```
  1017  
  1018  Reply:
  1019  
  1020  ```json
  1021  {}
  1022  ```
  1023  
  1024  ### `Reset password`
  1025  
  1026  Allows a user to reset his password without being logged in.
  1027  
  1028  **Route:** `POST /v1/user/password/reset`
  1029  
  1030  **Params:**
  1031  
  1032  | Parameter | Type | Description | Required |
  1033  |-|-|-|-|
  1034  | email | string | The email of the user whose password should be reset. | Yes |
  1035  | verificationtoken | string | The verification token which is sent to the user's email address. | Yes |
  1036  | newpassword | String | The new password for the user. | Yes |
  1037  
  1038  **Results:**
  1039  
  1040  | Parameter | Type | Description |
  1041  |-|-|-|
  1042  | verificationtoken | String | This command is special because it has to be called twice, the 2nd time the caller needs to supply the `verificationtoken` |
  1043  
  1044  
  1045  The reset password command is special.  It must be called **twice** with different
  1046  parameters.
  1047  
  1048  For the 1st call, it should be called with only an `email` parameter. On success
  1049  it shall send an email to the address provided by `email` and return `200 OK`.
  1050  
  1051  The email shall include a link in the following format:
  1052  
  1053  ```
  1054  /v1/user/password/reset?email=abc@example.com&verificationtoken=f1c2042d36c8603517cf24768b6475e18745943e4c6a20bc0001f52a2a6f9bde
  1055  ```
  1056  
  1057  On failure, the call shall return `400 Bad Request` and one of the following
  1058  error codes:
  1059  - [`ErrorStatusMalformedEmail`](#ErrorStatusMalformedEmail)
  1060  
  1061  For the 2nd call, it should be called with `email`, `token`, and `newpassword`
  1062  parameters.
  1063  
  1064  On failure, the call shall return `400 Bad Request` and one of the following
  1065  error codes:
  1066  - [`ErrorStatusVerificationTokenInvalid`](#ErrorStatusVerificationTokenInvalid)
  1067  - [`ErrorStatusVerificationTokenExpired`](#ErrorStatusVerificationTokenExpired)
  1068  - [`ErrorStatusMalformedPassword`](#ErrorStatusMalformedPassword)
  1069  
  1070  **Example for the 1st call**
  1071  
  1072  Request:
  1073  
  1074  ```json
  1075  {
  1076    "email": "6b87b6ebb0c80cb7@example.com"
  1077  }
  1078  ```
  1079  
  1080  Reply:
  1081  
  1082  ```json
  1083  {}
  1084  ```
  1085  
  1086  **Example for the 2nd call**
  1087  
  1088  Request:
  1089  
  1090  ```json
  1091  {
  1092    "email": "6b87b6ebb0c80cb7@example.com",
  1093    "verificationtoken": "f1c2042d36c8603517cf24768b6475e18745943e4c6a20bc0001f52a2a6f9bde",
  1094    "newpassword": "6b87b6ebb0c80cb7"
  1095  }
  1096  ```
  1097  
  1098  Reply:
  1099  
  1100  ```json
  1101  {
  1102    "verificationtoken": "f1c2042d36c8603517cf24768b6475e18745943e4c6a20bc0001f52a2a6f9bde"
  1103  }
  1104  ```
  1105  
  1106  ### `Proposal paywall details`
  1107  Retrieve paywall details that can be used to purchase proposal credits.
  1108  Proposal paywalls are only valid for one tx.  The user can purchase as many
  1109  proposal credits as they would like with that one tx. Proposal paywalls expire
  1110  after a set duration.  To verify that a payment has been made,
  1111  politeiawww polls the paywall address until the paywall is either paid or it
  1112  expires. A proposal paywall cannot be generated until the user has paid their
  1113  user registration fee.
  1114  
  1115  **Route:** `GET /v1/user/payments/paywall`
  1116  
  1117  **Params:** none
  1118  
  1119  **Results:**
  1120  
  1121  | Parameter | Type | Description |
  1122  |-|-|-|
  1123  | creditprice | uint64 | Price per proposal credit in atoms. |
  1124  | paywalladdress | string | Proposal paywall address. |
  1125  | paywalltxnotbefore | string | Minimum timestamp for paywall tx. |
  1126  On failure the call shall return `400 Bad Request` and one of the following
  1127  error codes:
  1128  - [`ErrorStatusUserNotPaid`](#ErrorStatusUserNotPaid)
  1129  
  1130  **Example**
  1131  
  1132  Request:
  1133  
  1134  ```json
  1135  {}
  1136  ```
  1137  
  1138  Reply:
  1139  
  1140  ```json
  1141  {
  1142    "creditprice": 10000000,
  1143    "paywalladdress": "TsRBnD2mnZX1upPMFNoQ1ckYr9Y4TZyuGTV",
  1144    "paywalltxnotbefore": 1532445975
  1145  }
  1146  ```
  1147  
  1148  ### `Proposal paywall tx details`
  1149  Retrieve paywall details that can be used to purchase proposal credits.
  1150  Proposal paywalls are only valid for one tx.  The user can purchase as many
  1151  proposal credits as they would like with that one tx. Proposal paywalls expire
  1152  after a set duration.  To verify that a payment has been made,
  1153  politeiawww polls the paywall address until the paywall is either paid or it
  1154  expires. A proposal paywall cannot be generated until the user has paid their
  1155  user registration fee.
  1156  
  1157  **Route:** `GET /v1/user/payments/paywalltx`
  1158  
  1159  **Params:**
  1160  | Parameter | Type | Description | Required |
  1161  |-----------|------|-------------|----------|
  1162  | userid | string | The unique id of the user. | Yes |
  1163  
  1164  **Results:**
  1165  
  1166  | Parameter | Type | Description |
  1167  |-|-|-|
  1168  | txid | string | Transaction id. |
  1169  | txamount | uint64 | Transaction amount in atoms. |
  1170  | confirmations | uint64 | Confirmations the transaction had on the network |
  1171  
  1172  **Example**
  1173  
  1174  Request:
  1175  
  1176  ```json
  1177  {
  1178    "userid": "1"
  1179  }
  1180  ```
  1181  
  1182  Reply:
  1183  
  1184  ```json
  1185  {
  1186    "txid": "ff0207a03b761cb409c7677c5b5521562302653d2236c92d016dd47e0ae37bf7",
  1187    "txamount": 10000000,
  1188    "confirmations": 2
  1189  }
  1190  ```
  1191  
  1192  ### `User proposal credits`
  1193  Request a list of the user's unspent and spent proposal credits.
  1194  
  1195  **Route:** `GET /v1/user/payments/credits`
  1196  
  1197  **Params:** none
  1198  
  1199  **Results:**
  1200  
  1201  | Parameter | Type | Description |
  1202  |-|-|-|
  1203  | unspentcredits | array of [`ProposalCredit`](#proposal-credit)'s | The user's unspent proposal credits |
  1204  | spentcredits | array of [`ProposalCredit`](#proposal-credit)'s | The user's spent proposal credits |
  1205  
  1206  **Example**
  1207  
  1208  Request:
  1209  
  1210  ```json
  1211  {}
  1212  ```
  1213  
  1214  Reply:
  1215  
  1216  ```json
  1217  {
  1218    "unspentcredits": [{
  1219      "paywallid": 2,
  1220      "price": 10000000,
  1221      "datepurchased": 1532438228,
  1222      "txid": "ff0207a03b761cb409c7677c5b5521562302653d2236c92d016dd47e0ae37bf7"
  1223    }],
  1224    "spentcredits": [{
  1225      "paywallid": 1,
  1226      "price": 10000000,
  1227      "datepurchased": 1532437363,
  1228      "txid": "1b6df077a0a745314dab58887c56c4261270bb7a809692fad8157a99a0c46477"
  1229    }]
  1230  }
  1231  ```
  1232  
  1233  ### `Policy`
  1234  
  1235  Retrieve server policy.  The returned values contain various maxima that the
  1236  client SHALL observe.
  1237  
  1238  **Route:** `GET /v1/policy`
  1239  
  1240  **Params:** none
  1241  
  1242  **Results:**
  1243  
  1244  | | Type | Description |
  1245  |-|-|-|
  1246  | minpasswordlength | number | minimum number of characters accepted for user passwords |
  1247  | minusernamelength | number | minimum number of characters accepted for username |
  1248  | maxusernamelength | number | maximum number of characters accepted for username |
  1249  | usernamesupportedchars | array of strings | the regular expression of a valid username |
  1250  | paywallenabled | bool | is paywall enabled |
  1251  | proposallistpagesize | number | maximum number of proposals returned for the routes that return lists of proposals |
  1252  | userlistpagesize | number | maximum number of users returned for the routes that return lists of users |
  1253  | maximages | number | maximum number of images accepted when creating a new proposal |
  1254  | maximagesize | number | maximum image file size (in bytes) accepted when creating a new proposal |
  1255  | maxmds | number | maximum number of markdown files accepted when creating a new proposal |
  1256  | maxmdsize | number | maximum markdown file size (in bytes) accepted when creating a new proposal |
  1257  | validmimetypes | array of strings | list of all acceptable MIME types that can be communicated between client and server. |
  1258  | maxproposalnamelength | number | max length of a proposal name |
  1259  | minproposalnamelength | number | min length of a proposal name |
  1260  | proposalnamesupportedchars | array of strings | the regular expression of a valid proposal name |
  1261  | maxcommentlength | number | maximum number of characters accepted for comments |
  1262  | backendpublickey | string |  |
  1263  | tokenprefixlength | number | The length of token prefix needed
  1264  | buildinformation | []string | build information including module commit hashes |
  1265  | IndexFilename | string | required filename for the proposal index.md file |
  1266  | MinLinkbyPeriod | number | Minimum required period, in seconds, for the proposal linkby period |
  1267  | MaxLinkByPeriod | number | Maximum allowed period, in seconds, for the proposal linkby period |
  1268  | MinVoteDuration | number | Minimum allowed vote duration |
  1269  | MaxVoteDuration | number | Maximum allowed vote duration |
  1270  
  1271  **Example**
  1272  
  1273  Request:
  1274  
  1275  ```
  1276  /v1/policy
  1277  ```
  1278  
  1279  Reply:
  1280  
  1281  ```json
  1282  {
  1283    "minpasswordlength": 8,
  1284    "minusernamelength": 3,
  1285    "maxusernamelength": 30,
  1286    "usernamesupportedchars": [
  1287      "A-z", "0-9", ".", ":", ";", ",", "-", " ", "@", "+"
  1288    ],
  1289    "proposallistpagesize": 20,
  1290    "maximages": 5,
  1291    "maximagesize": 524288,
  1292    "maxmds": 1,
  1293    "maxmdsize": 524288,
  1294    "validmimetypes": [
  1295      "image/png",
  1296      "text/plain",
  1297      "text/plain; charset=utf-8"
  1298    ],
  1299    "paywallenabled": true,
  1300    "proposalnamesupportedchars": [
  1301       "A-z", "0-9", "&", ".", ":", ";", ",", "-", " ", "@", "+", "#"
  1302    ],
  1303    "maxcommentlength": 8000,
  1304    "backendpublickey": "",
  1305    "minproposalnamelength": 8,
  1306    "maxproposalnamelength": 80,
  1307    "tokenprefixlength": 7,
  1308    "minvoteduration": 2016,
  1309    "maxvoteduration": 4032
  1310  }
  1311  ```
  1312  
  1313  ### `Proposal details`
  1314  
  1315  Retrieve proposal and its details. This request can be made with the full
  1316  censorship token or its 7 character prefix. This route will return only
  1317  vetted proposals.
  1318  
  1319  **Routes:** `GET /v1/proposals/{token}`
  1320  
  1321  **Params:**
  1322  
  1323  | Parameter | Type | Description | Required |
  1324  |-|-|-|-|
  1325  | token | string | Token is the unique censorship token that identifies a specific proposal. | Yes |
  1326  | version | string | Proposal Version. The latest version is the default when no version is specified. | No |
  1327  
  1328  **Results:**
  1329  
  1330  | | Type | Description |
  1331  |-|-|-|
  1332  | proposal | [`Proposal`](#proposal) | The proposal with the provided token. |
  1333  
  1334  On failure the call shall return `400 Bad Request` and one of the following
  1335  error codes:
  1336  - [`ErrorStatusProposalNotFound`](#ErrorStatusProposalNotFound)
  1337  
  1338  **Example**
  1339  
  1340  Request:
  1341  
  1342  The request params should be provided within the URL:
  1343  
  1344  ```
  1345  /v1/proposals/f1c2042d36c8603517cf24768b6475e18745943e4c6a20bc0001f52a2a6f9bde?version=2
  1346  ```
  1347  
  1348  Reply:
  1349  
  1350  ```json
  1351  {
  1352    "proposal": {
  1353      "name": "My Proposal",
  1354      "status": 3,
  1355      "timestamp": 1508146426,
  1356      "version": 2,
  1357      "files": [{
  1358        "name": "index.md",
  1359        "mime": "text/plain; charset=utf-8",
  1360        "digest": "0dd10219cd79342198085cbe6f737bd54efe119b24c84cbc053023ed6b7da4c8",
  1361        "payload": "VGhpcyBpcyBhIGRlc2NyaXB0aW9u"
  1362      }],
  1363      "censorshiprecord": {
  1364        "token": "c378e0735b5650c9e79f70113323077b107b0d778547f0d40592955668f21ebf",
  1365        "merkle": "0dd10219cd79342198085cbe6f737bd54efe119b24c84cbc053023ed6b7da4c8",
  1366        "signature": "f5ea17d547d8347a2f2d77edcb7e89fcc96613d7aaff1f2a26761779763d77688b57b423f1e7d2da8cd433ef2cfe6f58c7cf1c43065fa6716a03a3726d902d0a"
  1367      }
  1368    }
  1369  }
  1370  ```
  1371  
  1372  ### `Batch proposals`
  1373  
  1374  Retrieve the proposal details for a list of proposals.  This route wil not
  1375  return the proposal files.  The number of proposals that may be requested is
  1376  limited by the `ProposalListPageSize` property, which is provided via
  1377  [`Policy`](#policy).  This route will return only vetted proposals.
  1378  
  1379  **Routes:** `POST /v1/proposals/batch`
  1380  
  1381  **Params:**
  1382  
  1383  | Parameter | Type | Description | Required |
  1384  |-|-|-|-|
  1385  | tokens | []string | Array of censorship tokens of the proposals to be retrieved | Yes |
  1386  
  1387  **Results:**
  1388  
  1389  | Parameter | Type | Description |
  1390  |-|-|-|
  1391  | proposals | [][`Proposal`](#proposal) | Array of proposals |
  1392  
  1393  On failure the call shall return `400 Bad Request` and one of the following
  1394  error codes:
  1395  - [`ErrorStatusMaxProposalsExceededPolicy`](#ErrorStatusMaxProposalsExceededPolicy)
  1396  - [`ErrorStatusInvalidCensorshipToken`](#ErrorStatusInvalidCensorshipToken)
  1397  - [`ErrorStatusProposalNotFound`](#ErrorStatusProposalNotFound)
  1398  
  1399  **Example**
  1400  
  1401  Request:
  1402  
  1403  ```
  1404  /v1/proposals/batch
  1405  ```
  1406  
  1407  ```json
  1408  {
  1409    "tokens": [
  1410      "c9aaf64f9474a0c2aa2227363e3ba575e1926acd4257deba42dc6d5ab85f2cd2",
  1411      "f08dc22069f854856e27a6cb107e10064a85b85b2a4db41755d54f90bd30b84f"
  1412    ]
  1413  }
  1414  ```
  1415  
  1416  Reply:
  1417  
  1418  ```json
  1419  {
  1420      "proposals": [
  1421          {
  1422              "name": "Sample proposal 1",
  1423              "state": 2,
  1424              "status": 4,
  1425              "timestamp": 1561637933,
  1426              "userid": "bda3852b-f9e8-49a3-924a-147303b7d6b8",
  1427              "username": "username",
  1428              "publickey": "e008f83793c023321d54f283698c47fb50083489501a8c3b4b020b7c92930cb9",
  1429              "signature": "9c05c50b67c74d7c7e80be702afe123f46ddb417583bcd97674073d0d5ddc35804bec88b01d158bc1ab89bdb21e3cabbb4f290365c375ca226f8652d8dc01602",
  1430              "files": [],
  1431              "numcomments": 0,
  1432              "version": "1",
  1433              "publishedat": 1561637933,
  1434              "censorshiprecord": {
  1435                  "token": "c9aaf64f9474a0c2aa2227363e3ba575e1926acd4257deba42dc6d5ab85f2cd2",
  1436                  "merkle": "ab7d4fe5d89a1110b0c684d89a48558efaeb0247d13ba8a79200d7fdbde91559",
  1437                  "signature": "8860999e0df2b9b7cc727f2ebc6c32fd26a8c9bb7660524fefbf85202ea4e1296699544acdcc723d70708f9f1561007bac1c4d250eb5aa5ebdecea224a8fd105"
  1438              }
  1439          },
  1440          {
  1441              "name": "Sample Proposal 2",
  1442              "state": 2,
  1443              "status": 4,
  1444              "timestamp": 1560824670,
  1445              "userid": "6bd802af-42cc-47af-b1dc-412f93f21689",
  1446              "username": "user2",
  1447              "publickey": "ceaca7ba3579620968a1720e0748f3005802a2fd9e5afe0c7916f79c70234664",
  1448              "signature": "ea41d5f8808892488185d18447f5b8c9d77c0d65932464d5742c1d22dbb0c975b42aaddcb1dae4f5d4a4423f4965c8af4a9273d48faae1f0531abe3039608001",
  1449              "files": [],
  1450              "numcomments": 3,
  1451              "version": "1",
  1452              "publishedat": 1560824670,
  1453              "censorshiprecord": {
  1454                  "token": "f08dc22069f854856e27a6cb107e10064a85b85b2a4db41755d54f90bd30b84f",
  1455                  "merkle": "34745ec2aee7ba0bf3111c66f8484efb32bfea3bfe6cdcc46420adc1c7d181cc",
  1456                  "signature": "f0638afa9466ec3e4954f64e77929a0dd22d05b685180eaf36816e6cd65237760d4485be8afee04b824665acc809856aeabe9eade48f23a99b7be42e4508ac05"
  1457              }
  1458          }
  1459      ]
  1460  }
  1461  ```
  1462  
  1463  ### `Batch vote summary`
  1464  
  1465  Retrieve the vote summaries for a list of proposals.  The number of vote
  1466  summaries that may be requested is limited by the `ProposalListPageSize`
  1467  property, which is provided via [`Policy`](#policy).
  1468  
  1469  **Routes:** `POST /v1/proposals/batchvotesummary`
  1470  
  1471  **Params:**
  1472  
  1473  | Parameter | Type | Description | Required |
  1474  |-|-|-|-|
  1475  | tokens | []string | Array of censorship tokens of the requested vote summaries | Yes |
  1476  
  1477  **Results:**
  1478  
  1479  | Parameter | Type | Description |
  1480  |-|-|-|
  1481  | bestblock | uint64 | Current block height |
  1482  | summaries | map[string][`VoteSummary`](#vote-summary) | Map of [token]VoteSummary |
  1483  
  1484  On failure the call shall return `400 Bad Request` on the following error code:
  1485  - [`ErrorStatusMaxProposalsExceededPolicy`](#ErrorStatusMaxProposalsExceededPolicy)
  1486  - [`ErrorStatusInvalidCensorshipToken`](#ErrorStatusInvalidCensorshipToken)
  1487  - [`ErrorStatusProposalNotFound`](#ErrorStatusProposalNotFound)
  1488  
  1489  **Example**
  1490  
  1491  Request:
  1492  
  1493  ```
  1494  /v1/proposals/batchvotesummary
  1495  ```
  1496  
  1497  ```json
  1498  {
  1499    "tokens": [
  1500      "f08dc22069f854856e27a6cb107e10064a85b85b2a4db41755d54f90bd30b84f",
  1501      "c9aaf64f9474a0c2aa2227363e3ba575e1926acd4257deba42dc6d5ab85f2cd2"
  1502    ]
  1503  }
  1504  ```
  1505  
  1506  Reply:
  1507  
  1508  ```json
  1509  {
  1510    "bestblock": 243994,
  1511    "summaries": {
  1512      "f08dc22069f854856e27a6cb107e10064a85b85b2a4db41755d54f90bd30b84f": {
  1513        "status": 4,
  1514        "eligibletickets": 5267,
  1515        "duration": 2016,
  1516        "endheight": 231614,
  1517        "quorumpercentage": 20,
  1518        "passpercentage": 60,
  1519        "results": [
  1520          {
  1521            "option": {
  1522              "id": "no",
  1523              "description": "Don't approve proposal",
  1524              "bits": 1
  1525            },
  1526            "votesreceived": 3
  1527          },
  1528          {
  1529            "option": {
  1530              "id": "yes",
  1531              "description": "Approve proposal",
  1532              "bits": 2
  1533            },
  1534            "votesreceived": 2
  1535          }
  1536        ]
  1537      },
  1538      "c9aaf64f9474a0c2aa2227363e3ba575e1926acd4257deba42dc6d5ab85f2cd2": {
  1539        "status": 4,
  1540        "eligibletickets": 5270,
  1541        "duration": 2016,
  1542        "endheight": 229602,
  1543        "quorumpercentage": 20,
  1544        "passpercentage": 60,
  1545        "results": [
  1546          {
  1547            "option": {
  1548              "id": "no",
  1549              "description": "Don't approve proposal",
  1550              "bits": 1
  1551            },
  1552            "votesreceived": 1
  1553          },
  1554          {
  1555            "option": {
  1556              "id": "yes",
  1557              "description": "Approve proposal",
  1558              "bits": 2
  1559            },
  1560            "votesreceived": 4
  1561          }
  1562        ]
  1563      }
  1564    }
  1565  }
  1566  ```
  1567  
  1568  ### `Cast votes`
  1569  
  1570  This is a batched call that casts multiple votes to multiple proposals.
  1571  
  1572  Note that the webserver does not interpret the plugin structures. These are
  1573  forwarded as-is to the politeia daemon.
  1574  
  1575  **Route:** `POST /v1/proposals/castvotes`
  1576  
  1577  **Params:**
  1578  
  1579  | Parameter | Type | Description | Required |
  1580  |-|-|-|-|
  1581  | votes | array of CastVote | All votes | Yes |
  1582  
  1583  **CastVote:**
  1584  
  1585  | | Type | Description |
  1586  | - | - | - |
  1587  | token | string | Censorship token |
  1588  | ticket | string | Ticket hash |
  1589  | votebit | string | String encoded vote bit |
  1590  | signature | string | signature of Token+Ticket+VoteBit |
  1591  
  1592  **Results:**
  1593  
  1594  | | Type | Description |
  1595  | - | - | - |
  1596  | receipts | array of CastVoteReply  | Receipts for all cast votes. This appears in the same order and index as the votes that went in. |
  1597  
  1598  **CastVoteReply:**
  1599  
  1600  | | Type | Description |
  1601  | - | - | - |
  1602  | clientsignature | string | Signature that was sent in via CastVote |
  1603  | signature | string | Signature of ClientSignature |
  1604  | error | string | Error, "" if there was no error |
  1605  
  1606  **Example**
  1607  
  1608  Request:
  1609  
  1610  ``` json
  1611  {
  1612    "votes": [{
  1613      "token":"642eb2f3798090b3234d8787aaba046f1f4409436d40994643213b63cb3f41da",
  1614      "ticket":"1257089bfa5223739c27dd10150de71962442f57ee176389c79932c22536b31b",
  1615      "votebit":"2",
  1616      "signature":"1f05c95fd0c59b0ee68733bbc645437124702e2af40fe37f01f15784a161b8ebae432fcfc5c9388e8f7409e6f02976182eda3bffa5df5de968f40faf2d993a9992"
  1617      },{
  1618        "token":"642eb2f3798090b3234d8787aaba046f1f4409436d40994643213b63cb3f41da",
  1619        "ticket":"1c1e0b6968813f8321e721598f9510afae6acaa8576b64297e34fd5777d8d417",
  1620        "votebit":"2",
  1621        "signature":"1ff92d0025ea7ff283e4991b6fcdd6c87958f5ba5ba34863c075650a8b16dc23906f639ab83d034d6146de109afca7c0c92a00c60f36640846f679fb6ff2d7f966"
  1622      }
  1623    ]
  1624  }
  1625  ```
  1626  
  1627  Reply:
  1628  
  1629  ```json
  1630  {
  1631    "receipts": [{
  1632      "clientsignature":"1f05c95fd0c59b0ee68733bbc645437124702e2af40fe37f01f15784a161b8ebae432fcfc5c9388e8f7409e6f02976182eda3bffa5df5de968f40faf2d993a9992",
  1633      "signature":"1bc19bf3ee2da7b0a9a54ae944e42e7b9e8953fce0c122b0a0a540e900535ea7ae3c5f2bba8266025d797b0dd4e37f0d21ed2f974b246528ae162a3719ed0808",
  1634      "error":""
  1635    },{
  1636      "clientsignature":"1ff92d0025ea7ff283e4991b6fcdd6c87958f5ba5ba34863c075650a8b16dc23906f639ab83d034d6146de109afca7c0c92a00c60f36640846f679fb6ff2d7f966",
  1637      "signature":"dbd24b1205c3c81a1d8a5736d769e1d6fd37ea517c15934e4b2042df65567e8c4029137eec8fb03fdcf40ecfe5a5eaa2bd36f485c6597328f543d5c283de5e0a",
  1638      "error":""
  1639    }]
  1640  }
  1641  ```
  1642  
  1643  ### `Vote results`
  1644  
  1645  Retrieve vote results for a specified censorship token. If the voting period
  1646  has not yet started for the given proposal a reply is returned with all fields
  1647  set to their zero value.
  1648  
  1649  Note that the webserver does not interpret the plugin structures. These are
  1650  forwarded as-is to the politeia daemon.
  1651  
  1652  **Route:** `GET /v1/proposals/{token}/votes`
  1653  
  1654  **Params:** none
  1655  
  1656  **Results:**
  1657  
  1658  | | Type | Description |
  1659  | - | - | - |
  1660  | vote | Vote | Vote details |
  1661  | castvotes | array of CastVote  | Cast vote details |
  1662  | startvotereply | StartVoteReply | Vote details (eligible tickets, start block etc) |
  1663  
  1664  
  1665  On failure the call shall return `400 Bad Request` and one of the following
  1666  error codes:
  1667  - [`ErrorStatusProposalNotFound`](#ErrorStatusProposalNotFound)
  1668  - [`ErrorStatusWrongStatus`](#ErrorStatusWrongStatus)
  1669  
  1670  **Example**
  1671  
  1672  Request:
  1673  `GET /V1/proposals/642eb2f3798090b3234d8787aaba046f1f4409436d40994643213b63cb3f41da/votes`
  1674  
  1675  
  1676  Reply:
  1677  
  1678  ```json
  1679  {
  1680    "vote": {
  1681      "token":"642eb2f3798090b3234d8787aaba046f1f4409436d40994643213b63cb3f41da",
  1682      "mask":3,
  1683      "duration":2016,
  1684      "Options": [{
  1685        "id":"no",
  1686        "description":"Don't approve proposal",
  1687        "bits":1
  1688      },{
  1689        "id":"yes",
  1690        "description":"Approve proposal",
  1691        "bits":2
  1692      }]
  1693    },
  1694    "castvotes": [{
  1695      "token":"642eb2f3798090b3234d8787aaba046f1f4409436d40994643213b63cb3f41da",
  1696      "ticket":"91832123c3f04c0783fb51d93bffd6f641ce3e951c30a29e15fb9986f23817c0",
  1697      "votebit":"2",
  1698      "signature":"208e614662fd7719df82687b72578cfb1f5e54fd05287e67683397b77e1819d4ff5c2029117d1d01bfa5c4637b7661ad95319f455c264ed4b4637382ffee5d5d9e"
  1699    },{
  1700      "token":"642eb2f3798090b3234d8787aaba046f1f4409436d40994643213b63cb3f41da",
  1701      "ticket":"cf3943767a35136252f69118b291b47006308e4215de41673ab118736e26605e",
  1702      "votebit":"2",
  1703      "signature":"1f8b3c8207fa67d91a65d8742e5026044ccebd6b4865579a1f75d6e9a40a56f9a96e091397d2ec9f8fca773c68e961b93fe380a694aceecfd8f9b972f1e4d59db9"
  1704    }],
  1705    "startvotereply": {
  1706      "startblockheight":"282899",
  1707      "startblockhash":"00000000017236b62ff1ce136328e6fb4bcd171801a281ce0a662e63cbc4c4fa",
  1708      "endheight":"284915",
  1709      "eligibletickets":[
  1710        "000011e329fe0359ea1d2070d927c93971232c1118502dddf0b7f1014bf38d97",
  1711        "0004b0f8b2883a2150749b2c8ba05652b02220e98895999fd96df790384888f9",
  1712        "00107166c5fc5c322ecda3748a1896f4a2de6672aae25014123d2cedc83e8f42",
  1713        "002272cf4788c3f726c30472f9c97d2ce66b997b5762ff4df6a05c4761272413"
  1714      ]
  1715    }
  1716  }
  1717  ```
  1718  
  1719  ### `User Comments Likes`
  1720  
  1721  Retrieve the comment votes for the current logged in user given a proposal token
  1722  
  1723  **Route:** `GET v1/user/proposals/{token}/commentslikes`
  1724  
  1725  **Params:** none
  1726  
  1727  **Results:**
  1728  
  1729  | | Type | Description |
  1730  | - | - | - |
  1731  | commentslikes | array of CommentLike | Likes issued by the current user |
  1732  
  1733  **CommentLike:**
  1734  
  1735  | | Type | Description |
  1736  | - | - | - |
  1737  | action | string | Up or downvote (1, -1) |
  1738  | commentid | string | Comment ID |
  1739  | token | string | Proposal censorship token |
  1740  
  1741  **Example:**
  1742  
  1743  Request:
  1744  Path: `v1/user/proposals/8a11057fb910564a7d2506430505c3991f59e35f8a7757b8000a032505b254d8/commentslikes`
  1745  
  1746  Reply:
  1747  ```json
  1748    {
  1749      "commentslikes":
  1750      [
  1751        {
  1752          "action":"-1",
  1753          "commentid":"1",
  1754          "token":"8a11057fb910564a7d2506430505c3991f59e35f8a7757b8000a032505b254d8"
  1755        },
  1756        {
  1757          "action":"1",
  1758          "commentid":"2",
  1759          "token":"8a11057fb910564a7d2506430505c3991f59e35f8a7757b8000a032505b254d8"
  1760        }
  1761      ]
  1762    }
  1763  ```
  1764  
  1765  ### `Token inventory`
  1766  
  1767  Retrieve the censorship record tokens of all proposals in the inventory. The
  1768  tokens are categorized by stage of the voting process and sorted according to
  1769  the rules listed below. Unvetted proposal tokens are only returned to admins.
  1770  Unvetted proposals include unvreviewed and censored proposals.
  1771  
  1772  Sorted by record timestamp in descending order:
  1773  Pre, Abandonded, Unreviewed, Censored
  1774  
  1775  Sorted by voting period end block height in descending order:
  1776  Active, Approved, Rejected
  1777  
  1778  **Route:** `GET v1/proposals/tokeninventory`
  1779  
  1780  **Params:** none
  1781  
  1782  **Results:**
  1783  
  1784  | | Type | Description |
  1785  | - | - | - |
  1786  | pre | []string | Tokens of all vetted proposals that are pre-vote. |
  1787  | active | []string | Tokens of all vetted proposals with an active voting period. |
  1788  | approved | []string | Tokens of all vetted proposals that have been approved by a vote. |
  1789  | rejected | []string | Tokens of all vetted proposals that have been rejected by a vote. |
  1790  | abandoned | []string | Tokens of all vetted proposals that have been abandoned. |
  1791  | unreviewed | []string | Tokens of all unreviewed proposals. |
  1792  | censored | []string | Tokens of all censored proposals. |
  1793  
  1794  **Example:**
  1795  Request:
  1796  Path: `v1/proposals/tokeninventory`
  1797  
  1798  Reply:
  1799  
  1800  ```json
  1801  {
  1802    "pre": [
  1803      "567ec4cdca78362f725dbb2b8b5161991fe6ba3bb6da1ad3f99067dd4712e48e"
  1804    ],
  1805    "active": [
  1806      "79cb792d8a15e83ce6809b2846f4dfdd04a65f5aa674c04926599fabf80c1b62"
  1807    ],
  1808    "approved": [],
  1809    "rejected": [],
  1810    "abandoned": [
  1811      "99376fbf7b79e30a7ff778743da46e04ae3b360109fa71011930f4c9a15c4ef5"
  1812    ]
  1813  }
  1814  ```
  1815  
  1816  ### `Set TOTP`
  1817  
  1818  This user route requests a new TOTP secret to be generated by the server.  It
  1819  will return a Key/Image pair that can be used to save the key pair to
  1820  a TOTP app of the users' choice. 
  1821  
  1822  If the user already has a TOTP set, they must also add a code generated from
  1823  the currently set secret.
  1824  
  1825  For now we just have 'basic' TOTP added, but in the future we can add different 
  1826  or custom types of TOTP.
  1827  
  1828  **Route:** `POST /v1/user/totp`
  1829  
  1830  **Params:**
  1831  
  1832  | Parameter | Type | Description | Required |
  1833  |-|-|-|-|
  1834  | type | TOTPMethodT | The type of TOTP that the user wants generated | Yes |
  1835  | code | string | A code generated by | Yes |
  1836  
  1837  **Results:** 
  1838  
  1839  | | Type | Description |
  1840  | - | - | - |
  1841  | key | string | The secret key generated by the server. |
  1842  | image | string | The 'image' of the secret that can be used to generate a QRcode. |
  1843  
  1844  On success the call shall return `200 OK`.
  1845  
  1846  On failure the call shall return `400 Bad Request` and one of the following error codes:
  1847  - [`ErrorStatusTOTPFailedValidation`](#ErrorStatusTOTPFailedValidation)
  1848  - [`ErrorStatusInvalidInput`](#ErrorStatusInvalidInput)
  1849  
  1850  **Example:**
  1851  
  1852  Request:
  1853  
  1854  ```json
  1855  {
  1856    "type":"1",
  1857    "code":"994411"
  1858  }
  1859  ```
  1860  
  1861  Reply:
  1862  
  1863  ```json
  1864  {
  1865    "key":"",
  1866    "image":"",
  1867  }
  1868  ```
  1869  
  1870  ### `Verify TOTP`
  1871  
  1872  This verify and confirms the user's previous requested new TOTP secret with a
  1873  code generated by their TOTP app with the secret key provided from the SetTOTP 
  1874  request.
  1875  
  1876  **Route:** `POST /v1/user/verifytotp`
  1877  
  1878  **Params:**
  1879  
  1880  | Parameter | Type | Description | Required |
  1881  |-|-|-|-|
  1882  | code | string | The TOTP code generate from the user's secret key. | Yes |
  1883  
  1884  **Results:** none
  1885  
  1886  On success the call shall return `200 OK`.
  1887  
  1888  On failure the call shall return `400 Bad Request` and one of the following error codes:
  1889  - [`ErrorStatusTOTPFailedValidation`](#ErrorStatusTOTPFailedValidation)
  1890  
  1891  **Example:**
  1892  
  1893  Request:
  1894  
  1895  The request params should be provided within the URL:
  1896  
  1897  ```json
  1898  {
  1899    "code":"994411"
  1900  }
  1901  ```
  1902  
  1903  Reply:
  1904  
  1905  ```json
  1906  {}
  1907  ```
  1908  
  1909  ### `Error codes`
  1910  
  1911  | Status | Value | Description |
  1912  |-|-|-|
  1913  | <a name="ErrorStatusInvalid">ErrorStatusInvalid</a> | 0 | The operation returned an invalid status. This shall be considered a bug. |
  1914  | <a name="ErrorStatusInvalidPassword">ErrorStatusInvalidPassword</a> | 1 | The password is invalid. |
  1915  | <a name="ErrorStatusMalformedEmail">ErrorStatusMalformedEmail</a> | 2 | The provided email address was malformed. |
  1916  | <a name="ErrorStatusVerificationTokenInvalid">ErrorStatusVerificationTokenInvalid</a> | 3 | The provided user activation token is invalid. |
  1917  | <a name="ErrorStatusVerificationTokenExpired">ErrorStatusVerificationTokenExpired</a> | 4 | The provided user activation token is expired. |
  1918  | <a name="ErrorStatusProposalMissingFiles">ErrorStatusProposalMissingFiles</a> | 5 | The provided proposal does not have files. This error may include additional context: index file is missing - "index.md". |
  1919  | <a name="ErrorStatusProposalNotFound">ErrorStatusProposalNotFound</a> | 6 | The requested proposal does not exist. |
  1920  | <a name="ErrorStatusProposalDuplicateFilenames">ErrorStatusProposalDuplicateFilenames</a> | 7 | The provided proposal has duplicate files. This error is provided with additional context: the duplicate name(s). |
  1921  | <a name="ErrorStatusProposalInvalidTitle">ErrorStatusProposalInvalidTitle</a> | 8 | The provided proposal title is invalid. This error is provided with additional context: the regular expression accepted. |
  1922  | <a name="ErrorStatusMaxMDsExceededPolicy">ErrorStatusMaxMDsExceededPolicy</a> | 9 | The submitted proposal has too many markdown files. Limits can be obtained by issuing the [Policy](#policy) command. |
  1923  | <a name="ErrorStatusMaxImagesExceededPolicy">ErrorStatusMaxImagesExceededPolicy</a> | 10 | The submitted proposal has too many images. Limits can be obtained by issuing the [Policy](#policy) command. |
  1924  | <a name="ErrorStatusMaxMDSizeExceededPolicy">ErrorStatusMaxMDSizeExceededPolicy</a> | 11 | The submitted proposal markdown is too large. Limits can be obtained by issuing the [Policy](#policy) command. |
  1925  | <a name="ErrorStatusMaxImageSizeExceededPolicy">ErrorStatusMaxImageSizeExceededPolicy</a> | 12 | The submitted proposal has one or more images that are too large. Limits can be obtained by issuing the [Policy](#policy) command. |
  1926  | <a name="ErrorStatusMalformedPassword">ErrorStatusMalformedPassword</a> | 13 | The provided password was malformed. |
  1927  | <a name="ErrorStatusCommentNotFound">ErrorStatusCommentNotFound</a> | 14 | The requested comment does not exist. |
  1928  | <a name="ErrorStatusInvalidFilename">ErrorStatusInvalidFilename</a> | 15 | The filename was invalid. |
  1929  | <a name="ErrorStatusInvalidFileDigest">ErrorStatusInvalidFileDigest</a> | 16 | The digest (SHA-256 checksum) provided for one of the proposal files was incorrect. This error is provided with additional context: The name of the file with the invalid digest. |
  1930  | <a name="ErrorStatusInvalidBase64">ErrorStatusInvalidBase64</a> | 17 | The name of the file with the invalid encoding.The Base64 encoding provided for one of the proposal files was incorrect. This error is provided with additional context: the name of the file with the invalid encoding. |
  1931  | <a name="ErrorStatusInvalidMIMEType">ErrorStatusInvalidMIMEType</a> | 18 | The MIME type provided for one of the proposal files was not the same as the one derived from the file's content. This error is provided with additional context: The name of the file with the invalid MIME type and the MIME type detected for the file's content. |
  1932  | <a name="ErrorStatusUnsupportedMIMEType">ErrorStatusUnsupportedMIMEType</a> | 19 | The MIME type provided for one of the proposal files is not supported. This error is provided with additional context: The name of the file with the unsupported MIME type and the MIME type that is unsupported. |
  1933  | <a name="ErrorStatusInvalidPropStatusTransition">ErrorStatusInvalidPropStatusTransition</a> | 20 | The provided proposal cannot be changed to the given status. |
  1934  | <a name="ErrorStatusInvalidPublicKey">ErrorStatusInvalidPublicKey</a> | 21 | Invalid public key. |
  1935  | <a name="ErrorStatusNoPublicKey">ErrorStatusNoPublicKey</a> | 22 | User does not have an active public key. |
  1936  | <a name="ErrorStatusInvalidSignature">ErrorStatusInvalidSignature</a> | 23 | Invalid signature. |
  1937  | <a name="ErrorStatusInvalidInput">ErrorStatusInvalidInput</a> | 24 | Invalid input. |
  1938  | <a name="ErrorStatusInvalidSigningKey">ErrorStatusInvalidSigningKey</a> | 25 | Invalid signing key. |
  1939  | <a name="ErrorStatusCommentLengthExceededPolicy">ErrorStatusCommentLengthExceededPolicy</a> | 26 | The submitted comment length is too large. |
  1940  | <a name="ErrorStatusUserNotFound">ErrorStatusUserNotFound</a> | 27 | The user was not found. |
  1941  | <a name="ErrorStatusWrongStatus">ErrorStatusWrongStatus</a> | 28 | The proposal has the wrong status. |
  1942  | <a name="ErrorStatusNotLoggedIn">ErrorStatusNotLoggedIn</a> | 29 | The user must be logged in for this action. |
  1943  | <a name="ErrorStatusUserNotPaid">ErrorStatusUserNotPaid</a> | 30 | The user hasn't paid the registration fee. |
  1944  | <a name="ErrorStatusReviewerAdminEqualsAuthor">ErrorStatusReviewerAdminEqualsAuthor</a> | 31 | The user cannot change the status of his own proposal. |
  1945  | <a name="ErrorStatusMalformedUsername">ErrorStatusMalformedUsername</a> | 32 | The provided username was malformed. |
  1946  | <a name="ErrorStatusDuplicateUsername">ErrorStatusDuplicateUsername</a> | 33 | The provided username is already taken by another user. |
  1947  | <a name="ErrorStatusVerificationTokenUnexpired">ErrorStatusVerificationTokenUnexpired</a> | 34 | A verification token has already been generated and hasn't expired yet. |
  1948  | <a name="ErrorStatusCannotVerifyPayment">ErrorStatusCannotVerifyPayment</a> | 35 | The server cannot verify the payment at this time, please try again later. |
  1949  | <a name="ErrorStatusDuplicatePublicKey">ErrorStatusDuplicatePublicKey</a> | 36 | The public key provided is already taken by another user. |
  1950  | <a name="ErrorStatusInvalidPropVoteStatus">ErrorStatusInvalidPropVoteStatus</a> | 37 | Invalid proposal vote status. |
  1951  | <a name="ErrorStatusUserLocked">ErrorStatusUserLocked</a> | 38 | User locked due to too many login attempts. |
  1952  | <a name="ErrorStatusNoProposalCredits">ErrorStatusNoProposalCredits</a> | 39 | No proposal credits. |
  1953  | <a name="ErrorStatusInvalidUserManageAction">ErrorStatusInvalidUserManageAction</a> | 40 | Invalid action for editing a user. |
  1954  | <a name="ErrorStatusUserActionNotAllowed">ErrorStatusUserActionNotAllowed</a> | 41 | User action is not allowed. |
  1955  | <a name="ErrorStatusWrongVoteStatus">ErrorStatusWrongVoteStatus</a> | 42 | The proposal has the wrong vote status for the action to be performed. |
  1956  | <a name="ErrorStatusCannotVoteOnPropComment">ErrorStatusCannotVoteOnPropComment</a> | 44 | Cannot vote on proposal comment. |
  1957  | <a name="ErrorStatusChangeMessageCannotBeBlank">ErrorStatusChangeMessageCannotBeBlank</a> | 45 | Status change message cannot be blank. |
  1958  | <a name="ErrorStatusCensorReasonCannotBeBlank">ErrorStatusCensorReasonCannotBeBlank</a> | 46 | Censor comment reason cannot be blank. |
  1959  | <a name="ErrorStatusCannotCensorComment">ErrorStatusCannotCensorComment</a> | 47 | Cannot censor comment. |
  1960  | <a name="ErrorStatusUserNotAuthor">ErrorStatusUserNotAuthor</a> | 48 | User is not the proposal author. |
  1961  | <a name="ErrorStatusVoteNotAuthorized">ErrorStatusVoteNotAuthorized</a> | 49 | Vote has not been authorized. |
  1962  | <a name="ErrorStatusVoteAlreadyAuthorized">ErrorStatusVoteAlreadyAuthorized</a> | 50 | Vote has already been authorized. |
  1963  | <a name="ErrorStatusInvalidAuthVoteAction">ErrorStatusInvalidAuthVoteAction</a> | 51 | Invalid authorize vote action. |
  1964  | <a name="ErrorStatusUserDeactivated">ErrorStatusUserDeactivated</a> | 52 | Cannot login because user account is deactivated. |
  1965  | <a name="ErrorStatusInvalidPropVoteBits">ErrorStatusInvalidPropVoteBits</a> | 53 | Invalid proposal vote option bits. |
  1966  | <a name="ErrorStatusInvalidPropVoteParams">ErrorStatusInvalidPropVoteParams</a> | 54 | Invalid proposal vote parameters. |
  1967  | <a name="ErrorStatusEmailNotVerified">ErrorStatusEmailNotVerified</a> | 55 | Cannot login because user's email is not yet verified. |
  1968  | <a name="ErrorStatusInvalidUUID">ErrorStatusInvalidUUID</a> | 56 | Invalid user UUID. |
  1969  | <a name="ErrorStatusInvalidLikeCommentAction">ErrorStatusInvalidLikeCommentAction</a> | 57 | Invalid like comment action. |
  1970  | <a name="ErrorStatusInvalidCensorshipToken">ErrorStatusInvalidCensorshipToken</a> | 58 | Invalid proposal censorship token. |
  1971  | <a name="ErrorStatusEmailAlreadyVerified">ErrorStatusEmailAlreadyVerified</a> | 59 | Email address is already verified. |
  1972  | <a name="ErrorStatusNoProposalChanges">ErrorStatusNoProposalChanges</a> | 60 | No changes found in proposal. |
  1973  | <a name="ErrorStatusMaxProposalsExceedsPolicy">ErrorStatusMaxProposalsExceededPolicy</a> | 61 | Number of proposals requested exceeded the ProposalListPageSize. |
  1974  | <a name="ErrorStatusDuplicateComment">ErrorStatusDuplicateComment</a> | 62 | Duplicate comment. |
  1975  | <a name="ErrorStatusInvalidLogin">ErrorStatusInvalidLogin</a> | 63 | Invalid login credentials. |
  1976  | <a name="ErrorStatusCommentIsCensored">ErrorStatusCommentIsCensored</a> | 64 | Comment is censored. |
  1977  | <a name="ErrorStatusInvalidProposalVersion">ErrorStatusInvalidProposalVersion</a> | 65 | Invalid proposal version.  |
  1978  | <a name="ErrorStatusMetadataInvalid">ErrorStatusMetadataInvalid</a> | 66 | Invalid proposal metadata.  |
  1979  | <a name="ErrorStatusMetadataMissing">ErrorStatusMetadataMissing</a> | 67 | Missing proposal metadata. |
  1980  | <a name="ErrorStatusMetadataDigestInvalid">ErrorStatusMetadataDigestInvalid</a> | 68 | Proposal metadata digest invalid.  |
  1981  | <a name="ErrorStatusInvalidVoteType">ErrorStatusInvalidVoteType</a> | 69 | Invalid vote type. |
  1982  | <a name="ErrorStatusInvalidVoteOptions">ErrorStatusInvalidVoteOptions</a> | 70 | Invalid vote option.  |
  1983  | <a name="ErrorStatusLinkByDeadlineNotMet">ErrorStatusLinkByDeadlineNotMet</a> | 71 | Linkby not met yet.  |
  1984  | <a name="ErrorStatusNoLinkedProposals">ErrorStatusNoLinkedProposals</a> | 72 | No linked proposals.  |
  1985  | <a name="ErrorStatusInvalidLinkTo">ErrorStatusInvalidLinkTo</a> | 73 | Invalid propsoal linkto. |
  1986  | <a name="ErrorStatusInvalidLinkBy">ErrorStatusInvalidLinkBy</a> | 74 | Invalid proposal linkby.  |
  1987  | <a name="ErrorStatusInvalidRunoffVote">ErrorStatusInvalidRunoffVote</a> | 75 | Invalid runoff vote. |
  1988  | <a name="ErrorStatusWrongProposalType">ErrorStatusWrongProposalType</a> | 76 | Wrong proposal type. |
  1989  | <a name="ErrorStatusTOTPFailedValidation">ErrorStatusTOTPFailedValidation</a> | 77 | TOTP code provided doesn't failed validation with current key. |
  1990  | <a name="ErrorStatusTOTPInvalidType">ErrorStatusTOTPInvalidType</a> | 78 | Invalid TOTP Type. |
  1991  | <a name="ErrorStatusRequiresTOTPCode">ErrorStatusRequiresTOTPCode</a> | 79 | User has verified TOTP secret and login requires code. |
  1992  | <a name="ErrorStatusTOTPWaitForNewCode">ErrorStatusTOTPWaitForNewCode</a> | 80 | Must wait until next TOTP code window before another login attempt. |
  1993  
  1994  
  1995  ### `Proposal status codes`
  1996  
  1997  | Status | Value | Description |
  1998  |-|-|-|
  1999  | <a name="PropStatusInvalid">PropStatusInvalid</a>| 0 | An invalid status. This shall be considered a bug. |
  2000  | <a name="PropStatusNotFound">PropStatusNotFound</a> | 1 | The proposal was not found. |
  2001  | <a name="PropStatusNotReviewed">PropStatusNotReviewed</a> | 2 | The proposal has not been reviewed by an admin. |
  2002  | <a name="PropStatusCensored">PropStatusCensored</a> | 3 | The proposal has been censored by an admin. |
  2003  | <a name="PropStatusPublic">PropStatusPublic</a> | 4 | The proposal has been published by an admin. |
  2004  | <a name="PropStatusUnreviewedChanges">PropStatusUnreviewedChanges</a> | 5 | The proposal has not been rewieved by an admin yet and has been edited by the author. |
  2005  | <a name="PropStatusAbandoned">PropStatusAbandoned</a> | 6 | The proposal is public and has been deemed abandoned by an admin. |
  2006  
  2007  ### `Vote types`
  2008  | Status | Value | Description |
  2009  |-|-|-|
  2010  | <a name="VoteTypeInvalid">VoteTypeInvalid</a>| 0 | An invalid vote type. This shall be considered a bug. |
  2011  | <a name="VoteTypeStandard">VoteTypeStandard</a>| 1 | A simple approve or reject proposal vote where the winner is the voting option that has met the specified pass and quorum requirements. |
  2012  | <a name="VoteTypeRunoff">VoteType</a>| 2 | A runoff vote that multiple proposals compete in. All proposals are voted on like normal, but there can only be one winner in a runoff vote. The winner is the proposal that meets the quorum requirement, meets the pass requirement, and that has the most net yes votes. The winning proposal is considered approved and all other proposals are considered rejected. If no proposals meet the quorum and pass requirements then all proposals are considered rejected. Note: in a runoff vote it is possible for a proposal to meet the quorum and pass requirements but still be rejected if it does not have the most net yes votes. |
  2013  
  2014  ### `User edit actions`
  2015  
  2016  | Status | Value | Description |
  2017  |-|-|-|
  2018  | <a name="UserManageInvalid">UserManageInvalid</a>| 0 | An invalid action. This shall be considered a bug. |
  2019  | <a name="UserManageExpireNewUserVerification">UserManageExpireNewUserVerification</a> | 1 | Expires the new user verification token. |
  2020  | <a name="UserManageExpireUpdateKeyVerification">UserManageExpireUpdateKeyVerification</a> | 2 | Expires the update key verification token. |
  2021  | <a name="UserManageExpireResetPasswordVerification">UserManageExpireResetPasswordVerification</a> | 3 | Expires the reset password verification token. |
  2022  | <a name="UserManageClearUserPaywall">UserManageClearUserPaywall</a> | 4 | Clears the user's paywall. |
  2023  | <a name="UserManageUnlock">UserManageUnlock</a> | 5 | Unlocks a user's account. |
  2024  | <a name="UserManageDeactivate">UserManageDeactivate</a> | 6 | Deactivates a user's account so that they are unable to login. |
  2025  | <a name="UserManageReactivate">UserManageReactivate</a> | 7 | Reactivates a user's account. |
  2026  
  2027  ### `User`
  2028  
  2029  | | Type | Description |
  2030  |-|-|-|
  2031  | id | string | The unique id of the user. |
  2032  | email | string | Email address. |
  2033  | username | string | Unique username. |
  2034  | isadmin | boolean | Whether the user is an admin or not. |
  2035  | newuserpaywalladdress | string | The address in which to send the transaction containing the `newuserpaywallamount`.  If the user has already paid, this field will be empty or not present. |
  2036  | newuserpaywallamount | int64 | The amount of DCR (in atoms) to send to `newuserpaywalladdress`.  If the user has already paid, this field will be empty or not present. |
  2037  | newuserpaywalltxnotbefore | int64 | The minimum UNIX time (in seconds) required for the block containing the transaction sent to `newuserpaywalladdress`.  If the user has already paid, this field will be empty or not present. |
  2038  | newuserpaywalltx | string | The transaction used to pay the `newuserpaywallamount` at `newuserpaywalladdress`. |
  2039  | newuserpaywallpollexpiry | int64 | The UNIX time (in seconds) for when the server will stop polling the server for transactions at `newuserpaywalladdress`. |
  2040  | newuserverificationtoken | string | The verification token which is sent to the user's email address. |
  2041  | newuserverificationexpiry | int64 | The UNIX time (in seconds) for when the `newuserverificationtoken` expires. |
  2042  | updatekeyverificationtoken | string | The verification token which is sent to the user's email address. |
  2043  | updatekeyverificationexpiry | int64 | The UNIX time (in seconds) for when the `updatekeyverificationtoken` expires. |
  2044  | resetpasswordverificationtoken | string | The verification token which is sent to the user's email address. |
  2045  | resetpasswordverificationexpiry | int64 | The UNIX time (in seconds) for when the `resetpasswordverificationtoken` expires. |
  2046  | lastlogintime | int64 | The UNIX timestamp of the last login date; it will be 0 if the user has not logged in before. |
  2047  | failedloginattempts | uint64 | The number of consecutive failed login attempts. |
  2048  | islocked | boolean | Whether the user account is locked due to too many failed login attempts. |
  2049  | isdeactivated | boolean | Whether the user account is deactivated. Deactivated accounts cannot login. |
  2050  | identities | array of [`Identity`](#identity)s | Identities, both activated and deactivated, of the user. |
  2051  | proposalcredits | uint64 | The number of available proposal credits the user has. |
  2052  | emailnotifications | uint64 | A flag storing the user's preferences for email notifications. Individual notification preferences are stored in bits of the number, and are [documented below](#emailnotifications). |
  2053  
  2054  ### `Email notifications`
  2055  
  2056  These are the available email notifications that can be sent.
  2057  
  2058  | Description | Value |
  2059  |-|-|
  2060  | **For my proposals** |
  2061  | Proposal status change (approved/censored) | `1 << 0` |
  2062  | Proposal vote started | `1 << 1` |
  2063  | **For others' proposals** |
  2064  | New proposal published | `1 << 2` |
  2065  | Proposal edited | `1 << 3` |
  2066  | Proposal vote started | `1 << 4` |
  2067  | **Admins for others' proposals** |
  2068  | Proposal submitted for review | `1 << 5` |
  2069  | Proposal vote authorized | `1 << 6` |
  2070  
  2071  ### `Abridged User`
  2072  
  2073  This is a shortened representation of a user, used for lists.
  2074  
  2075  | | Type | Description |
  2076  |-|-|-|
  2077  | id | string | The unique id of the user. |
  2078  | email | string | Email address. |
  2079  | username | string | Unique username. |
  2080  
  2081  ### `Proposal`
  2082  
  2083  | | Type | Description |
  2084  |-|-|-|
  2085  | name | string | The name of the proposal. |
  2086  | state | number | Current state of the proposal. |
  2087  | status | number | Current status of the proposal. |
  2088  | timestamp | number | The unix time of the last update of the proposal. |
  2089  | userid | string | The ID of the user who created the proposal. |
  2090  | username | string | Proposal author's username. |
  2091  | publickey | string | The public key of the user who created the proposal. |
  2092  | signature | string | The signature of the merkle root, signed by the user who created the proposal. |
  2093  | numcomments | number | The number of comments on the proposal. This should be ignored for proposals which are not public. |
  2094  | version | string | The proposal version. |
  2095  | statatuschangemessage | string | Message associated to the status change (omitempty). |
  2096  | pubishedat | number | The timestamp of when the proposal was published (omitempty). |
  2097  | censoredat | number | The timestamp of when the proposal was censored (omitempty). |
  2098  | abandonedat | The timestamp of when the proposal was abandoned (omitempty). |
  2099  | linkto | string | Censorship token of proposal to link to (omitempty). |
  2100  | linkby | number | Unix timestamp of RFP link by deadline (omitempty). |
  2101  | files | [][`File`](#file)s | Proposal files. This property will only be populated for the [`Proposal details`](#proposal-details) call. |
  2102  | metadata | [][`Metadata`](#metadata) | Proposal metadata. This will contain a [`ProposalMetadata`](#proposal-metadata). |
  2103  | censorshiprecord | [`CensorshipRecord`](#censorship-record) | The censorship record that was created when the proposal was submitted. |
  2104  
  2105  ### `Identity`
  2106  
  2107  | | Type | Description |
  2108  |-|-|-|
  2109  | pubkey | string | The user's public key. |
  2110  | isactive | boolean | Whether or not the identity is active. |
  2111  
  2112  ### `File`
  2113  
  2114  | | Type | Description |
  2115  |-|-|-|
  2116  | name | string | Name is the suggested filename. There should be no filenames that are overlapping and the name shall be validated before being used. |
  2117  | mime | string | MIME type of the payload. Currently the system only supports md and png files. The server shall reject invalid MIME types. |
  2118  | digest | string | Digest is a SHA256 digest of the payload. The digest shall be verified by politeiad. |
  2119  | payload | string | Payload is the actual file content. It shall be base64 encoded. Files have size limits that can be obtained via the [`Policy`](#policy) call. The server shall strictly enforce policy limits. |
  2120  
  2121  ### `Metadata`
  2122  
  2123  | | Type | Description |
  2124  |-|-|-|
  2125  | Digest | string | SHA256 digest of the JSON encoded payload |
  2126  | Hint | string | Hint that describes the payload |
  2127  | Payload | string | Base64 encoded metadata content where the metadata content is JSON encoded. |
  2128  
  2129  ### `Proposal metadata`
  2130  | | Type | Description |
  2131  |-|-|-|
  2132  | Name | string | Proposal name. |
  2133  | LinkTo | string | Censorship token of the proposal to link to (optional). |
  2134  | LinkBy | int64 | Unix timestamp of the RFP deadline (optional). |
  2135  
  2136  ### `Vote summary`
  2137  
  2138  | | Type | Description |
  2139  |-|-|-|
  2140  | status | int | Status identifier |
  2141  | approved | bool | Has the proposal vote passed |
  2142  | type | [`VoteT`](#vote-types)| Vote type (omitempty) |
  2143  | eligibletickets | int | Total number of eligible tickets (omitempty) |
  2144  | duration | uint32 | Duration of the vote in blocks (omitempty) |
  2145  | endheight | uint64 | The chain height in which the vote will end (omitempty) |
  2146  | quorumpercentage | uint32 | Percent of eligible votes required for quorum (omitempty) |
  2147  | passpercentage | uint32 | Percent of total votes required to pass (omitempty) |
  2148  | optionsresult | array of VoteOptionResult | Option description along with the number of votes it has received (omitempty) |
  2149  
  2150  ### `Censorship record`
  2151  
  2152  | | Type | Description |
  2153  |-|-|-|
  2154  | token | string | The token is a 32 byte random number that was assigned to identify the submitted proposal. This is the key to later retrieve the submitted proposal from the system. |
  2155  | merkle | string | Merkle root of the proposal. This is defined as the sorted digests of all files proposal files. The client should cross verify this value. |
  2156  | signature | string | Signature of byte array representations of merkle+token. The token byte array is appended to the merkle root byte array and then signed. The client should verify the signature. |
  2157  
  2158  ### `Login reply`
  2159  
  2160  This object will be sent in the result body on a successful [`Login`](#login)
  2161  or [`Me`](#me) call.
  2162  
  2163  | Parameter | Type | Description |
  2164  |-|-|-|
  2165  | isadmin | boolean | This indicates if the user has publish/censor privileges. |
  2166  | userid | string | Unique user identifier. |
  2167  | email | string | Current user email address. |
  2168  | publickey | string | Current public key. |
  2169  | paywalladdress | String | The address in which to send the transaction containing the `paywallamount`.  If the user has already paid, this field will be empty or not present. |
  2170  | paywallamount | Int64 | The amount of DCR (in atoms) to send to `paywalladdress`.  If the user has already paid, this field will be empty or not present. |
  2171  | paywalltxnotbefore | Int64 | The minimum UNIX time (in seconds) required for the block containing the transaction sent to `paywalladdress`.  If the user has already paid, this field will be empty or not present. |
  2172  | lastlogintime | int64 | The UNIX timestamp of the last login date; it will be 0 if the user has not logged in before. |
  2173  | sessionmaxage | int64 | The UNIX timestamp of the session max age. |
  2174  
  2175  ### `Proposal credit`
  2176  A proposal credit allows the user to submit a new proposal.  Proposal credits are a spam prevention measure.  Credits are created when a user sends a payment to a proposal paywall. The user can request proposal paywall details using the [`Proposal paywall details`](#proposal-paywall-details) endpoint.  A credit is automatically spent every time a user submits a new proposal.
  2177  
  2178  | | Type | Description |
  2179  |-|-|-|
  2180  | paywallid | uint64 | The ID of the proposal paywall that created this credit. |
  2181  | price | uint64 | The price that the credit was purchased at in atoms. |
  2182  | datepurchased | int64 | A Unix timestamp of the purchase data. |
  2183  | txid | string | The txID of the Decred transaction that paid for this credit. |
  2184  
  2185  ## Websocket methods
  2186  
  2187  ### `WSHeader`
  2188  | Parameter | Type | Description | Required |
  2189  |-|-|-|-|
  2190  |Command|string|Type of JSON structure that follows the header|yes|
  2191  |ID|string|Client settable ID|no|
  2192  
  2193  **WSHeader** is required as a prefix to every other command on both the client
  2194  and server side.
  2195  
  2196  ### `WSError`
  2197  | Parameter | Type | Description | Required |
  2198  |-|-|-|-|
  2199  |Command|string|Type of JSON structure that follows the header|no|
  2200  |ID|string|Client settable ID|no|
  2201  |Errors|array of string|All errors that occurred during execution of the failed command|yes|
  2202  
  2203  **WSError** always flows from server to client.
  2204  
  2205  **example**
  2206  ```
  2207  {
  2208    "command": "error",
  2209    "id": "1"
  2210  }
  2211  {
  2212    "command": "subscribe",
  2213    "id": "1",
  2214    "errors": [
  2215      "invalid subscription pingo"
  2216    ]
  2217  }
  2218  ```
  2219  
  2220  ### `WSSubscribe`
  2221  | Parameter | Type | Description | Required |
  2222  |-|-|-|-|
  2223  |RPCS|array of string|Subscriptions|yes|
  2224  
  2225  Current valid subscriptions are `ping`.
  2226  
  2227  Sending additional `subscribe` commands will result in the old subscription
  2228  list being overwritten and thus an empty `rpcs` cancels all subscriptions.
  2229  
  2230  **WSSubscribe** always flows from client to server.
  2231  
  2232  **Example**
  2233  ```
  2234  {
  2235    "command": "subscribe",
  2236    "id": "1"
  2237  }
  2238  {
  2239    "rpcs": [
  2240      "ping"
  2241    ]
  2242  }
  2243  ```
  2244  
  2245  
  2246  ### `WSPing`
  2247  | Parameter | Type | Description | Required |
  2248  |-|-|-|-|
  2249  |Timestamp|int64|Server timestamp|yes|
  2250  
  2251  **WSPing** always flows from server to client.
  2252  
  2253  **example**
  2254  ```
  2255  {
  2256    "command": "ping"
  2257  }
  2258  {
  2259    "timestamp": 1547653596
  2260  }