Q-Apps API
Introduction
Welcome to the Qortal Q-Apps API documentation!
This section provides comprehensive information and resources for developers looking to build applications on top of Qortal's decentralized ecosystem.
Qortal Q-Apps API offers a powerful set of tools and endpoints that enable seamless integration with the Qortal blockchain. With these APIs, developers can harness the full potential of Qortal's decentralized infrastructure to create innovative applications, explore data, interact with the blockchain, and much more!
Whether you are a seasoned blockchain developer or just starting your journey, this documentation will guide you through the various aspects of the Qortal Q-Apps API.
You will find detailed explanations, commented code explaining each part of an API call, API call response examples, and explanations for the different terminology involved in building Q-Apps.
You can also check out our React tutorial guide on Youtube to gain practical knowledge on building a Q-App. The videos take you step-by-step through the process of building a Q-App, from starting up your React application, to deploying your Q-App to the Qortal network.
Join the growing community of Qortal developers and harness the potential of decentralized applications with the Q-Apps API. Together, let's shape the future of blockchain technology! Happy coding and building!
Major thanks to CalDescent for writing the intial version of this API!!
Resources
Each published item on QDN (Qortal Data Network) is referred to as a "resource". A resource could contain anything from a few characters of text, to a multi-layered directory structure containing thousands of files.
Resources are indexed on-chain, however the data payload is generally stored off-chain, and verified using an on-chain SHA-256 hash. Resources smaller than 240 bytes are fully on-chain, and the CHAIN_COMMENT service can be used to ensure this result, allowing faster data retrieval.
To publish a resource, a user must first register a name, and then include that name when publishing the data. Accounts without a registered name are unable to publish to QDN from a Q-App at this time.
Owning the name grants update privileges to the data. If that name is later sold or transferred, the permission to update that resource is moved to the new owner.
Each QDN resource has 3 important fields:
'Default' resources
A "default" resource refers to one without an identifier. For example, when a website is published via the UI, it will use the user's name and the service WEBSITE
. These do not have an identifier, and are therefore the "default" website for this name. When requesting or publishing data without an identifier, apps can either omit the identifier
key entirely, or include "identifier": "default"
to indicate that the resource(s) being queried or published do not have an identifier.
Service Types
Public services
The services below are intended to be used for publicly accessible data. The maximum file size is shown for each service that does not use the current general limit of 500 MB.
Private services
For the services below, data is encrypted for a single recipient, and can only be decrypted using the private key of the recipient's wallet.
Single vs multi-file resources
Some resources, such as those published with the IMAGE
or JSON
service, consist of a single file or piece of data (the image or the JSON string). This is the most common type of QDN resource, especially in the context of Q-Apps. These can be published by supplying a base64-encoded string containing the data.
Other resources, such as those published with the WEBSITE
, APP
, or GIF_REPOSITORY
service, can contain multiple files and directories. Publishing these kinds of files is not yet available for Q-Apps, however it is possible to retrieve multi-file resources that are already published. When retrieving this data (via FETCH_QDN_RESOURCE), a filepath
must be included to indicate the file that you would like to retrieve. There is no need to specify a filepath for single file resources, as these will automatically return the contents of the single file.
App-specific data
Some apps may want to make all QDN data for a particular service available. However, others may prefer to only deal with data that has been published by their app (if a specific format/schema is being used for instance).
Identifiers can be used to allow app developers to locate data that has been published by their app. The recommended approach for this is to use the app name as a prefix on all identifiers when publishing data.
For instance, an app called MyApp
could allow users to publish JSON data. The app could choose to prefix all identifiers with the string myapp_
, and then use a random string for each published resource (resulting in identifiers such as myapp_qR5ndZ8v
). Then, to locate data that has potentially been published by users of MyApp, it can later search the QDN database for items with "service": "JSON"
and "identifier": "myapp_"
. The SEARCH_QDN_RESOURCES action has a prefix
option in order to match identifiers beginning with the supplied string.
Note that QDN is a permissionless system, and therefore it's not possible to verify that a resource was actually published by the app. It is recommended that apps validate the contents of the resource to ensure it is formatted correctly, instead of making assumptions.
Updating resources
To update a resource, it can be overwritten by publishing with the same name
, service
, and identifier
combination. Note that the authenticated account must currently own the name in order to publish an update.
Categories
Resources can have an optional category
chosen from the following list.
Routing
If a non-existent filepath
is accessed, the default behaviour of QDN is to return a 404: File not found error
. This includes anything published using the WEBSITE service
.
However, routing is handled differently for anything published using the APP
service.
For apps, QDN automatically sends all unhandled requests to the index file (generally index.html). This allows the app to use custom routing, as it is able to listen on any path. If a file exists at a path, the file itself will be served, and so the request won't be sent to the index file.
It's recommended that all apps return a 404 page if a request isn't able to be routed.
Linking to other QDN websites / resources
The qortal://
protocol can be used to access QDN data from within Qortal websites and apps. The basic format is as follows:
1<a href="qortal://{service}/{name}/{identifier}/{path}">link text</a>
However, the system will support the omission of the identifier and/or path components to allow for simpler URL formats.
A simple link to another website can be achieved with this HTML code:
1<a href="qortal://WEBSITE/QortalDemo">link text</a>
To link to a specific page of another website:
1<a href="qortal://WEBSITE/QortalDemo/minting-leveling/index.html">link text</a>
To link to a standalone resource, such as an avatar
1<a href="qortal://THUMBNAIL/QortalDemo/qortal_avatar">avatar</a>
For cases where you would prefer to explicitly include an identifier (to remove ambiguity) you can use the keyword default to access a resource that doesn't have an identifier. For instance:
1<a href="qortal://WEBSITE/QortalDemo/default">link to root of website</a>
1<a href="qortal://WEBSITE/QortalDemo/default/minting-leveling/index.html">link to subpage of website</a>
Linking to other QDN images
The same applies for images, such as displaying an avatar:
1<img src="qortal://THUMBNAIL/QortalDemo/qortal_avatar" />
...or even an image from an entirely different website:
1<img src="qortal://WEBSITE/AlphaX/assets/img/logo.png" />
Integrating a Javascript app
Javascript apps allow for much more complex integrations with Qortal's blockchain data.
Built in variables
Q-Apps can access several variables that give information aboue the state of the app. These include:
The theme variable will contain the string 'light' or 'dark' depending on the active theme, while the context variable will contain the string 'gateway' if the app is being accessed through a gateway node.
Api Interaction
Direct API calls
The standard Qortal Core API is available to websites and apps, and can be called directly using a standard AJAX request, such as:
1async function getNameInfo(name) {2 const response = await fetch("/names/" + name);3 const nameData = await response.json();4 console.log("nameData: " + JSON.stringify(nameData));5}6const name = await getNameInfo("QortalDemo");
RESPONSE
1{2 "name": "QortalDemo",3 "reducedName": "q0rta1dem0",4 "owner": "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2",5 "data": "Registered Name on the Qortal Chain",6 "registered": 1628962032704,7 "isForSale": false8}
However, this only works for read-only data, such as looking up transactions, names, balances, etc. Also, since the address of the logged in account can't be retrieved from the core, apps can't show personalized data with this approach.
Via qortalRequest()
1const name = await qortalRequest({2 action: "GET_NAME_DATA",3 name: "QortalDemo"4});
RESPONSE
1{2 "name": "QortalDemo",3 "reducedName": "q0rta1dem0",4 "owner": "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2",5 "data": "Registered Name on the Qortal Chain",6 "registered": 1628962032704,7 "isForSale": false8}
qortalRequest
To take things a step further, the qortalRequest() function can be used to interact with the user, in order to:
In addition to the above, qortalRequest() also supports many read-only functions that are also available via direct core API calls. Using qortalRequest() helps with futureproofing, as the core APIs can be modified without breaking functionality of existing Q-Apps.
Making a request
Qortal core will automatically inject the qortalRequest()
javascript function to all websites/apps, which returns a Promise. This can be used to fetch data or publish data to the Qortal blockchain. This functionality supports async/await, as well as try/catch error handling.
1async function myfunction() {2 try {3 let res = await qortalRequest({4 action: "GET_ACCOUNT_DATA",5 address: "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2"6 });7 console.log(res); // Log the response to the console89 } catch(e) {10 console.log("Error: " + e);11 }12}13myfunction();
Timeouts
Request timeouts are handled automatically when using qortalRequest(). The timeout value will differ based on the action being used - see getDefaultTimeout()
in q-apps.js for the current values.
If a request times out it will throw an error - The request timed out
- which can be handled by the Q-App.
It is also possible to specify a custom timeout using qortalRequestWithTimeout(request, timeout)
, however this is discouraged. It's more reliable and futureproof to let the core handle the timeout values.
CREATE_POLL
Create a poll inside your Q-App. To get results of this poll, you would subsequently make a fetch call to /polls​/votes​/${pollName}
to get the voting results. The poll name must be unique or else it will throw an error.
This action requires user approval
1await qortalRequest({2 action: "CREATE_POLL",3 pollName: "A test poll 3",4 pollDescription: "Test description",5 pollOptions: ['option1, option2, option3'],6 pollOwnerAddress: 'QbpZL12Lh7K2y6xPZure4pix5jH6ViVrF2'7});
RESPONSE
1{2 "type": "CREATE_POLL",3 "timestamp": 1697285826221,4 "reference": "3Svgda6JMSoKW8xQreHRWwXfzWUqCG7NXae5bJDcezbGgK2km8VVbRGZXdEA3Q6LSDvG6hfk1xjXBawpBgxSAa2B",5 "fee": "0.01000000",6 "signature": "3jU9WpEPAvu9iL3cMfVd2AUmn9AijJRzkGCxVtXfpuUFZubM8AFDcbk5XA9m5AhPfsbMDFkSDzPJnkjeLA5GA59E",7 "txGroupId": 0,8 "approvalStatus": "NOT_REQUIRED",9 "creatorAddress": "Qhxphh7g5iNtxAyLLpPMZzp4X85yf2tVam",10 "owner": "QbpZL12Lh7K2y6xPZure4pix5jH6ViVrF2",11 "pollName": "A test poll 3",12 "description": "test description",13 "pollOptions": [14 {15 "optionName": "option1"16 },17 {18 "optionName": "option2"19 },20 {21 "optionName": "option3"22 }23 ]24}
DECRYPT_DATA
1const response = await qortalRequest({2 action: 'DECRYPT_DATA',3 encryptedData: base64, // has to be in base64 format4 publicKey: publicKey // requires the public key of the opposite user with whom you've created the encrypted data.5});
RESPONSE
1AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZ... // Decrypted data is returned in base64 format
DEPLOY_AT
DEPLOY_AT allows a user to create an AT (Automated Transaction) on the Qortal network. This AT can be used to create a crowdfund that pays out after certain funds are accumulated for example.
*Note: This action is for advanced users only. Please check Discord for more information on Deploying ATs. This action requires user approval.
1await qortalRequest({2 action: "DEPLOY_AT",3 creationBytes: "19bxFY2S32GVMj2CVdaBs6ekrUQxY2iDVbcTLA6sgHVeBMh8GXZmC9KVPcrid6qhJyPjdfDRh7jz4w2DGhJiHp6EdTJm5MVir9RU2avabWtFXdJbYiLVfr7VQybBtH2JDATESpeL5RAPTzCoesVCoQASVxAYhHL6J8tJoN6ZKugaQpMHccd45bbriMGzYZACu4pQGKfRGpbDXKVUzFjTLZjkbBfv13TjDgTEfUVD2JQ5dCgivb6Padq2oz9KB25kr9kEMXwtQUFLNmwRQHXebHiLFA4GAUDH8qpHTakhZhvBVqBrkyJvRaCpXkE2F6FfJaiYbSVty25QQGqQmrzMTmbYJjSRbrbEnUHmZJNdhgPybmrkN7iKPGj9gy7i5fTgu9t9bbumC3GZK3cNXJfZ885m4cNH4azCRHmQruyDcr5tXp1wnJcwPtkfn87HdgWee2ftLm8hrmrg27eUQgFjNgJr7TEuBmDmPxQCDZkLftnqdymNk6GgNJ5TXgH2tdSmpF5AEh5jRnV63M7tMMo9ezTuEhtachimUrJg5FpF6Q1BJm6Ytd24Hti8G6LCyXMvDvnWxzrgZXRHQVwaeAcpggxPQL4fx4FihwpRkRXmKV1dfjXkpEMB6vJEV9F73ThBwsD61d4N8GAJ7ubNU6BkEzkrqEedU2EDRVccJVaWN64hXmfDN9ygHSpk7TxhsvLrqAhW5H5nZDAcb25yiZowGhWewv8fy1mCtuhWBfzCPiNLSEakudrC2Z53ZZfGcsH4dih2REk6icdmKG5tAXa4tvqxkzdmSxGmqBTpJNqRdCCEYvAUKs6BsXWYSLzEr9wZ7UKSBG61jFm2ZzDYCqb6EZUWDRzL8nWBirGxGAgJ7jvTWUQtc4Q62sa8MEDQAnJLdcCzivwMnZ5udr5BPmRuhBNUbMDNBCC7CwmBpDLzMEWsa4junPfZXr8h9Y5wXyx9wZjwqq3DYNwYV8bgRTnRmxNuuhoWZiL9SxccUwvnTTD9VXPGKdPoWMZ7EWNv3LSrfxRrwoCLRvjtCEonjYN4hosvn61iR2QXdWajg3r5hH79S5M6GohpdKGKvbsttKjewkkdKVok4m8cn7JYx4F4vbS31zVXQ5VQA4m6R54qEUqEgSZM9i6BfckCLPx2ZznXoJ7UcErocUNZFfpfAqECcExRPnu1fqNd9GfGSQGBpvP6VVoowKSc1bVnJxTJfULwNJFa986Skm3B25rEMX2TAVgPFcJMzPLwctzTfMbYhc6nttPWrBZFSrqHcFyUaPPLK4aKkq6oPa1PA4Cgb4L9sQjksXB3tqnTFGa9ZsQE79QQHQrDVurRFh3fyMfvkAXyVycW1W4QBE6R4h7PvaNbDRXUQtQ8pcHRdY1BSUAXQp1u3XkNES7BmqjNxgDTcBMfUv3",4 name: "Test AT",5 description: "QORT/LTC cross-chain trade",6 type: "ACCT",7 tags: "Test ACCT QORT LTC",8 amount: 100000000, // 1 QORT9 assetId: 0,10 fee: 20000 // 0.0002 QORT11});
RESPONSE
1{2 "type": "DEPLOY_AT",3 "timestamp": 1696526612286,4 "reference": "61w5axRcoyUX9dEjQVotiNkrxuLSotHV8iwrfsF5BimLB9vBHuyZMoC59WY2nbcjUPHVw4QFcpEcQcSwxr5tXVXs",5 "fee": "0.01000000",6 "signature": "4R8MQAA1cqwYfDRC4KUV7nQYpooFHtM71XLFUxC9uX6Ni59CnswivvsqYVXJkzs3qY9QhHS5F4nEbX3tbXmgUjGE",7 "txGroupId": 0,8 "approvalStatus": "NOT_REQUIRED",9 "creatorAddress": "QWfYVQfuz2rVskYkpkVvLxL3kUPmBgKhHV",10 "name": "q-fund crowdfund",11 "description": "qortal-devfund-q-fund-campaign",12 "aTType": "crowdfund",13 "tags": "q-fund",14 "creationBytes": "1Pub6o13xyqfCZj8BMzmXsREVJR6h4xxpS2VPV1R2QwjP78r2ozxsNuvb28GWrT8FoTTQMGnVP7pNii6auUqYr2uunWfcxwhERbDgFdsJqtrJMpQNGB9GerAXYyiFiij35cP6eHw7BmALb3viT6VzqaXX9YB25iztekV5cTreJg7o2hRpFc9Rv8Z9dFXcD1Mm4WCaMaknUgchDi7qDnHA7JX8bn9EFD4WMG5nZHMsrmeqBHirURXr2dMxFprTBo187zztn9bFAmGdDBxgKg2qkPo7ZX3QFNEsUXeynXM7SJzHzdKaECxbefkPfA1nGENnM1Mto6rjWCX4KZk6QtrUtYBLGHo5XWkXGm9VJmywUbRdJviNbAN23VLBq2Q7AFAeGCkFSTYvomqjNUDUDNRjDH",15 "amount": "0.20000000",16 "assetId": 0,17 "aTAddress": "AJQRHEdunFaZpufYfCmqjKBoWYnU6j6jfa",18 "creatorPublicKey": "8i9bPX8Mf8wJRKf4GiSAqWzCBsCNkCtWPJ9hxuHMgGRo",19 "blocksToGoal": 37435,20 "goalValue": 25000,21 "userAddress": "QWfYVQfuz2rVskYkpkVvLxL3kUPmBgKhHV"22}
ENCRYPT_DATA
Encrypts data provided by the user. This handler takes in data, optionally in the form of a file, or a base64 string, and an array of public keys to perform group encryption. Returns the encrypted data in a JSON string.
1const encryptedData = await qortalRequest({2 action: 'ENCRYPT_DATA',3 file: file, // requires a file object4 base64: base64 // requires a base64 string if file object is not provided5 publicKeys: [] // Array of public keys of the users with whom you want to encrypt the data (optional, used for group encryption)6});
RESPONSE
1"cW9ydGFsR3JvdXBFbmNyeXB0ZWREYXRhmixnlZeFIMyu8mrCtewxFyGdWu9HBqfyvSLOlY7tl2e0tUbILFNblFyN5dzJYfJ1pLBZNUBmBc21mZ9CP0vWLpoUW65823McoD4oQ1HmaVhwZJRicAtelcimB3bMF6TlvthWCicvcoO6S76XI2vVI1WLEdUEFgbvt8cVfvDboz+GWbFRvNmADmKaXDeM8yAJVsRo19Ot6AEAAAA="
FETCH_BLOCK
Fetch block by signature
Equivalent to: /blocks/child/{signature}
1const response = await qortalRequest({2 action: "FETCH_BLOCK",3 signature: "875yGFUy1zHV2hmxNWzrhtn9S1zkeD7SQppwdXFysvTXrankCHCz4iyAUgCBM3GjvibbnyRQpriuy1cyu953U1u5uQdzuH3QjQivi9UVwz86z1Akn17MGd5Z5STjpDT7248K6vzMamuqDei57Znonr8GGgn8yyyABn35CbZUCeAuXju"4});
RESPONSE
1{2 "signature": "MPBrvZ8xt28tz2L6jdLnudJrudGoy22BBmkmfu5r7wU4QH3hbVBnxL7fzavR8YHx4SD8bdzgJJaHHeHgDL4D5UwTdhobAoxbFmyHLirnG1G6hgDmZDhKzmyEWCdoNGyn4bsLyKZJ4axo3yRHt7ZTUNLqq7hMc5rwTqYJX3FgyXncN3P",3 "version": 4,4 "reference": "875yGFUy1zHV2hmxNWzrhtn9S1zkeD7SQppwdXFysvTXrankCHCz4iyAUgCBM3GjvibbnyRQpriuy1cyu953U1u5uQdzuH3QjQivi9UVwz86z1Akn17MGd5Z5STjpDT7248K6vzMamuqDei57Znonr8GGgn8yyyABn35CbZUCeAuXju",5 "transactionCount": 0,6 "totalFees": "0.00003520",7 "transactionsSignature": "5yCkerB1Ed57vBPyWWH8ZR6Hv5LGC8zqBLPiLHKeQE1gNfc4yByQvSAHQKJZiqShWfpFEf9VmvmAwVsaFZrCqUe9",8 "height": 1139852,9 "timestamp": 1674130634871,10 "minterPublicKey": "6g5K1X4bZFWn1S3buye6qFMGTyZug4G96Gif4DZ2E7jV",11 "minterSignature": "4yyX2xrSQdzvZAFbvK8okwT2DDJMiTSin3wGio3858v1FXhXDT9qKC1RQfCrDNzgWA9L1gSQ8ypMZJ5y4MMMxe14",12 "atCount": 180,13 "atFees": "0.00003520",14 "encodedOnlineAccounts": "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",15 "onlineAccountsCount": 4707,16 "minterAddress": "QVLSru2TzBrgAmqJMzTwsBxwm98ABfGsdj"17}
Fetch block by height
Equivalent to: /blocks/byheight/{height}
1const response = await qortalRequest({2 action: "FETCH_BLOCK",3 height: "1139850"4});
RESPONSE
1// same response as 'Fetch block by signature'
Fetch a range of blocks
Equivalent to: /blocks/range/{height}
1const response = await qortalRequest({2 action: "FETCH_BLOCK_RANGE",3 height: "1139800",4 count: 20,5 reverse: false6});
RESPONSE
1[2 // an array of objects such as the response of 'Fetch block by signature'3]
FETCH_QDN_RESOURCE
Equivalent to: /arbitrary/{service}/{name}/{identifier}
1const response = await qortalRequest({2 action: "FETCH_QDN_RESOURCE",3 name: "QortalDemo",4 service: "THUMBNAIL",5 identifier: "qortal_avatar", // Optional. If omitted, the default resource is returned, or you can alternatively use the keyword "default"6 encoding: "base64", // Optional. If omitted, data is returned in raw form7 rebuild: false8});
RESPONSE
1// base64 encoding returns a base642AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAA1HbWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpd...
1// In this example I'm requesting a json that was saved to QDN (this is just an example- this exact resource doesn't exist)2const response = await qortalRequest({3 action: 'FETCH_QDN_RESOURCE',4 name: 'Q-Blog',5 service: 'BLOG_POST',6 identifier: 'q-blog-tester-2-blog-post-test-HDUgPk'7})
RESPONSE
1// If the encoding param is omitted the raw data is return. In this case a json.2{3 "title": "test zip",4 "createdAt": 1683806014297,5 "postContent": [6 {7 "type": "file",8 "version": 1,9 "content": {10 "name": "Q-Blog",11 "identifier": "qfile_qblog_X5uIea",12 "service": "FILE",13 "title": "tester2's file zip",14 "mimeType": "application/zip"15 },16 "id": "SkMHKY"17 }18 ],19 "layouts": {20 "rows": [21 {22 "ids": [23 "SkMHKY"24 ],25 "id": "UHZmoI",26 "type": "file"27 }28 ]29 },30 "layoutGeneralSettings": {31 "padding": 5,32 "blogPostType": "minimal"33 }34}
Fetch file from multi file QDN resource
Data is returned in the base64 format
1const response = await qortalRequest({2 action: "FETCH_QDN_RESOURCE",3 name: "QortalDemo",4 service: "WEBSITE",5 identifier: "default", // Optional. If omitted, the default resource is returned, or you can alternatively request that using the keyword "default", as shown here6 filepath: "index.html", // Required only for resources containing more than one file7 rebuild: false8});
GET_ACCOUNT_DATA
Equivalent to: /addresses/QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2
1const response = await qortalRequest({2 action: "GET_ACCOUNT_DATA",3 address: "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2"4});
RESPONSE
1{2 "address": "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2",3 "reference": "4uEPpCYsk2rCUsxksP72PeRtHaR5vQg9kWy6mLU377a7H4RJtCRFVCT6anPdfdXRs3p7f8KYo8LtZLmntQ7eNoks",4 "publicKey": "APLQ85zRbgRdrLTU7GgeTt35kvVhxmSjoCB4wX99HjYd",5 "defaultGroupId": 205,6 "flags": 0,7 "level": 0,8 "blocksMinted": 0,9 "blocksMintedAdjustment": 0,10 "blocksMintedPenalty": 011}
GET_ACCOUNT_NAMES
Equivalent to: /names/address/QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2
1const response = await qortalRequest({2 action: "GET_ACCOUNT_NAMES",3 address: "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2",4 limit: 20,5 offset: 0,6 reverse: true7});
RESPONSE
1[2 {3 "name": "QortalDemo",4 "owner": "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2"5 }6]
GET_BALANCE
Equivalent to: /addresses/balance/{name}
1const response = await qortalRequest({2 action: "GET_BALANCE",3 address: "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2"4});
RESPONSE
17.11
GET_DAY_SUMMARY
1const summary = await qortalRequest({2 action: "GET_DAY_SUMMARY"3});
RESPONSE
1{2 "blockCount": 1195,3 "assetsIssued": 0,4 "namesRegistered": 7,5 "transactionCountByType": {6 "PAYMENT": 31,7 "REGISTER_NAME": 7,8 "SELL_NAME": 7,9 "CANCEL_SELL_NAME": 1,10 "ARBITRARY": 94,11 "TRANSFER_ASSET": 1677,12 "DEPLOY_AT": 43,13 "MESSAGE": 61,14 "AT": 54,15 "GROUP_INVITE": 2,16 "JOIN_GROUP": 3,17 "REWARD_SHARE": 6018 },19 "totalTransactionCount": 204020}
GET_FRIENDS_LIST
This action requires user approval
Gets a user's friends list in an array of strings. Returns an error "Error in retrieving friends list" if it is not successful.
1const friendsList = await qortalRequest({2 action: "GET_FRIENDS_LIST"3});
RESPONSE
1[2 "Phil",3 "Qortal Seth",4 "Justin"5]
GET_NAME_DATA
Equivalent to: /names/QortalDemo
1const response = await qortalRequest({2 action: "GET_NAME_DATA",3 name: "QortalDemo"4});
RESPONSE
1{2 "name": "QortalDemo",3 "reducedName": "q0rta1dem0",4 "owner": "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2",5 "data": "Registered Name on the Qortal Chain",6 "registered": 1628962032704,7 "isForSale": false8}
GET_PRICE
Equivalent to: /crosschain/price/{blockchain}
The value of each Qortal unit is expressed in terms of 1 Qort multiplied by 1e8. Hence, if you receive a response value of 303366, you simply divide it by 1e8 to find its equivalent in Qort. This conversion will yield a result of 0.0030366 Qort.
1const response = await qortalRequest({2 action: "GET_PRICE",3 blockchain: "LITECOIN",4 // maxtrades: 10,5 inverse: true //Display price in terms of foreign currency per unit QORT6});
RESPONSE
1303366
GET_QDN_RESOURCE_METADATA
Equivalent to: /arbitrary/metadata/{service}/{name}/{identifier}
If the resource doesn't have metedata, a 404 will be returned
1const response = await qortalRequest({2 action: "GET_QDN_RESOURCE_METADATA",3 name: "Q-Blog",4 service: "BLOG_POST",5 identifier: "q-blog-qblog-post-Publishing-Blog-s-SncAO3" // Optional6});
RESPONSE
1{2 "title": "Publishing Blog Posts",3 "description": "Learn how to publish blog posts. There are two types of editors. Find out which one is for you!",4 "tags": [5 "v1.0x0",6 "t, v"7 ],8 "files": [9 "qortal-1682200171884"10 ],11 "mimeType": "text/vnd.graphviz"12}
GET_QDN_RESOURCE_PROPERTIES
Equivalent to: /arbitrary/resource/properties/{service}/{name}/{identifier}
1const response = await qortalRequest({2 action: "GET_QDN_RESOURCE_PROPERTIES",3 name: "QortalDemo",4 service: "THUMBNAIL",5 identifier: "qortal_avatar" // Optional6});
RESPONSE
1{2 "filename": "qortal-1684173273893",3 "mimeType": "video/mp4",4 "size": 237669875}
GET_QDN_RESOURCE_STATUS
Equivalent to: /arbitrary/resource/status/{service}/{name}/{identifier}
1const response = await qortalRequest({2 action: "GET_QDN_RESOURCE_STATUS",3 name: "QortalDemo",4 service: "THUMBNAIL",5 identifier: "qortal_avatar", // Optional6 build: true // Optional - request that the resource is fetched & built in the background7});
RESPONSE
1{2 "status": "READY",3 "id": "READY",4 "title": "Ready",5 "description": "Ready",6 "localChunkCount": 45,7 "totalChunkCount": 45,8 "percentLoaded": 100.09}
GET_QDN_RESOURCE_URL
Get URL to load a QDN resource. Note: this returns a "Resource does not exist" error if a non-existent resource is requested.
1let url = await qortalRequest({2 action: "GET_QDN_RESOURCE_URL",3 service: "THUMBNAIL",4 name: "QortalDemo",5 identifier: "qortal_avatar"6 // path: "filename.jpg" // optional - not needed if resource contains only one file7});8Get URL to load a QDN website9Note: this returns a "Resource does not exist" error if a non-existent resource is requested.1011let url = await qortalRequest({12 action: "GET_QDN_RESOURCE_URL",13 service: "WEBSITE",14 name: "QortalDemo",15});16Get URL to load a specific file from a QDN website17Note: this returns a "Resource does not exist" error if a non-existent resource is requested.1819let url = await qortalRequest({20 action: "GET_QDN_RESOURCE_URL",21 service: "WEBSITE",22 name: "AlphaX",23 path: "/assets/img/logo.png"24});
RESPONSE
1'/arbitrary/BLOG_POST/Q-Blog/q-blog-qblog-post-Publishing-Blog-s-SncAO3'
GET_PROFILE_DATA
Get a profile property. Returns a user's profile property data based on inputted key. This will return a string value if the property is any of the following: "tagline" or "bio". Both "wallets" and custom properties will return an object.
Custom properties are created by the user and can be any key-value pair. They are created by using the "SET_PROFILE_DATA" action. Trying to get a custom property that does not exist will return an error object {error: "Cannot find requested data"}.
1const profileData = await qortalRequest({2 action: "GET_PROFILE_DATA",3 property: "wallets"4});
RESPONSE
1{2 "btc": "12zcTs6EkpVcJCTPWTGYkqukW2W8iv81KA",3 "ltc": "LhqJGB78YajuuiysXZBhiF1YcttRNwzBgD",4 "doge": "D77Z9AZXhmbuKqRvTqoF7p4bmbGGdAaKPZ",5 "dgb": "DURXrj6V6yHbEKm529sW7yBKG3Gm1qWbqb",6 "rvn": "RCJJq72k5pzfczp51BZfi3CHLuq422JBF1",7 "arrr": "zs1shd0rle4yvnafwzl9nwqzvwxdx3ew803hjw0qc2zhvrx5vfxdtvmh8wgwjlpe5elrhszx4yyzme"8}
Get a profile custom property
1const profileData = await qortalRequest({2 action: "GET_PROFILE_DATA",3 property: "foo"4});
RESPONSE
1{2 newKey: "bar"3}
GET_USER_ACCOUNT
This action requires user approval
1const account = await qortalRequest({2 action: "GET_USER_ACCOUNT"3});
RESPONSE
1{2 "address": "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2",3 "publicKey": "APLQ85zRbgRdrLTU7GgeTt35kvVhxmSjoCB4wX99HjYd",4}
GET_USER_WALLET
Choose which coin you want to get the wallet for
This action requires user approval
1const response = await qortalRequest({2 action: "GET_USER_WALLET",3 coin: "QORT"4});
RESPONSE
17.11
GET_USER_WALLET_INFO
The GET_USER_WALLET_INFO endpoint retrieves detailed information for each address associated with a user's Hierarchical Deterministic (HD) BIP32 wallet. It provides a structured overview of wallet addresses, allowing users to manage and organize their cryptocurrency transactions efficiently.
This action requires user approval
1const response = await qortalRequestWithTimeout({2 action: "GET_USER_WALLET_INFO",3 coin: "BTC"4}, 15000);
RESPONSE
1[2 {3 "address": "1KyDZurCr2S15N2j1s4pUeH8fAQVT7VfdB",4 "path": [5 0,6 07 ],8 "value": 0,9 "pathAsString": "M/0/0",10 "transactionCount": 011 },12 {13 "address": "1DYn4oyypvyFCFL7Y5oDoAfmem88SucxEJ",14 "path": [15 0,16 117 ],18 "value": 0,19 "pathAsString": "M/0/1",20 "transactionCount": 021 },22 // Additional addresses omitted for brevity23]
GET_WALLET_BALANCE
This action requires user approval
1const response = await qortalRequest({2 action: "GET_WALLET_BALANCE",3 coin: "QORT"4});
RESPONSE
17.11
JOIN_GROUP
This action requires user approval
1const response = await qortalRequest({2 action: "JOIN_GROUP",3 groupId: 1004});
RESPONSE
1true
LINK_TO_QDN_RESOURCE
Note: an alternate method is to include <a href="qortal://WEBSITE/QortalDemo">link text</a>
within your HTML code.
1const handleLinkProgrammatically = async () => {2 await qortalRequest({3 action: "LINK_TO_QDN_RESOURCE",4 service: "WEBSITE",5 name: "QortalDemo",6 });7}89const handleLinkProgrammaticallyWithPath = async () => {10 await qortalRequest({11 action: "LINK_TO_QDN_RESOURCE",12 service: "WEBSITE",13 name: "QortalDemo",14 path: "/minting-leveling/index.html"15 });16}1718handleLinkProgramatically()19handleLinkProgrammaticallyWithPath()
LIST_QDN_RESOURCES
Equivalent to: /arbitrary/resources?
1const response = await qortalRequest({2 action: "LIST_QDN_RESOURCES",3 service: "THUMBNAIL",4 name: "QortalDemo", // Optional (exact match)5 identifier: "qortal_avatar", // Optional (exact match)6 default: true, // Optional7 includeStatus: false, // Optional - will take time to respond, so only request if necessary8 includeMetadata: false, // Optional - will take time to respond, so only request if necessary9 followedOnly: false, // Optional - include followed names only10 excludeBlocked: false, // Optional - exclude blocked content11 limit: 100,12 offset: 0,13 reverse: true14});
RESPONSE
1[2 // without metadata3 {4 "name": "crowetic",5 "service": "FILE",6 "identifier": "qfile_qblog_E1V14x",7 "size": 29499368 },9 // with metadata (includeMetadata: true)10 {11 "name": "crowetic",12 "service": "FILE",13 "identifier": "qfile_qblog_uPsr9L",14 "metadata": {15 "title": "Qortal-The-Future-Wallpaper",16 "description": "This is mostly a test of Q-Blog published image in file format on website links",17 "tags": [18 "Image testing"19 ],20 "category": "QORTAL",21 "categoryName": "Qortal",22 "mimeType": "image/png"23 },24 "size": 210843225 },26]
LIST_GROUPS
Equivalent to: /groups?
1const response = await qortalRequest({2 action: "LIST_GROUPS",3 limit: 100,4 offset: 0,5 reverse: true6});
RESPONSE
1[2 {3 "groupId": 150,4 "owner": "QRt11DVBnLaSDxr2KHvx92LdPrjhbhJtkj",5 "groupName": "animation station",6 "description": "freedom cartoons... made here",7 "created": 1638219000069,8 "isOpen": false,9 "approvalThreshold": "ONE",10 "minimumBlockDelay": 5,11 "maximumBlockDelay": 60,12 "memberCount": 113 },14 {15 "groupId": 121,16 "owner": "QLkRktaMTcYMKNMTxvLdh9rgsWbhVth2A1",17 "groupName": "anime",18 "description": "talk about it, watch it, whatever you like, this group is about anime",19 "created": 1624914222641,20 "isOpen": true,21 "approvalThreshold": "ONE",22 "minimumBlockDelay": 5,23 "maximumBlockDelay": 1440,24 "memberCount": 725 },26 ...27]
LISTS
GET_LIST_ITEMS
This action requires user approval
1const response = await qortalRequest({2 action: "GET_LIST_ITEMS",3 list_name: "blockedNames"4});
RESPONSE
1[ 'Q-Blog', 'Q-Mail']
ADD_LIST_ITEMS
This action requires user approval
1const response = await qortalRequest({2 action: "ADD_LIST_ITEMS",3 list_name: "blockedNames",4 items: ["QortalDemo"]5});67// the list will become [ 'Q-Blog', 'Q-Mail', 'QortalDemo]
RESPONSE
1true
DELETE_LIST_ITEM
This action requires user approval
1const response = await await qortalRequest({2 action: "DELETE_LIST_ITEM",3 list_name: "blockedNames",4 item: "Q-MAIL"5});6// the list will become [ 'Q-Blog', 'QortalDemo]
RESPONSE
1true
NOTIFICATIONS_PERMISSION
Request permission from the user to receive notifications from your Q-App
1const response = await qortalRequest({2 action: 'NOTIFICATIONS_PERMISSION'3})
Response if the user accepts the modal.
RESPONSE
1true
Response if the user declines the modal.
RESPONSE
1false
OPEN_NEW_TAB
Opens a new tab with the specified URL inside the Qortal UI
1const response = await qortalRequest({2 action: 'OPEN_NEW_TAB',3 qortalLink: 'qortal://APP/Ear-Bump/liked'4})
RESPONSE
1true
OPEN_PROFILE
Opens a user's profile if they have one. Note: this will open a modal with "This name has no profile" if that is the case.
1const profile = await qortalRequest({2 action: "OPEN_PROFILE",3 name: "Bester"4});
RESPONSE
1true
PUBLISH_QDN_RESOURCE
This action requires user approval
Note: this publishes a single file object or base64-encoded file. Compressed archive (zip) and multi-file resource publishing (such as a WEBSITE or GIF_REPOSITORY) is not yet supported via a Q-App. It may be added in a future update.
1const response = await qortalRequest({2 action: "PUBLISH_QDN_RESOURCE",3 name: "Demo", // Publisher must own the registered name - use GET_ACCOUNT_NAMES for a list4 service: "IMAGE",5 identifier: "myapp-image1234" // Optional6 data64: "base64_encoded_data", // base64 string. Remove this param if you are putting in a file. see next param.7 file: "file_object", // File Object. Remove this param if you are putting in a base64 string.8 // filename: "image.jpg", // Optional - to help apps determine the file's type9 // title: "Title", // Optional10 // description: "Description", // Optional11 // category: "TECHNOLOGY", // Optional12 // tag1: "any", // Optional13 // tag2: "strings", // Optional14 // tag3: "can", // Optional15 // tag4: "go", // Optional16 // tag5: "here", // Optional17 // encrypt: true, // Optional - to be used with a private service18 // recipientPublicKey: "publickeygoeshere" // Only required if encrypt is set to true19});
RESPONSE
1{2 "type": "ARBITRARY",3 "timestamp": 1684337616751,4 "reference": "4j2iPN5Xwgocs8Z32JB4UB63G87qS43kPyEwFmQMLvWBXtrSQwAfyx8S9CqQvbregnstXFKqXpkPT2dNdAscriT4",5 "fee": "0.00100000",6 "signature": "5Y6Jdyvo8n6JB44qC8i57x2gA3VXd7aah42GvnzkXL459vCWrRE5gae5TWbGqJxmKnk4p5ESHESv2FJfyB8bdzs9",7 "txGroupId": 0,8 "approvalStatus": "NOT_REQUIRED",9 "creatorAddress": "QMjCNsctvWLoDdPSRpHn6TF2j96iDr9YWm",10 "version": 5,11 "senderPublicKey": "Bjo1iUHJXbCb4LKabmE6KWNL5jSgCK36ypasoDgJG53U",12 "service": 777,13 "nonce": 0,14 "size": 496,15 "name": "Demo",16 "identifier": "myapp-image1234",17 "method": "PUT",18 "secret": "GELP1wMCyMAcwLWTvsAjsFoiR63BcAF7wmrhd1NVhjL",19 "compression": "ZIP",20 "data": "ArzaQASrXM74SDhWp6JhhmUBsocWRoVajZFtYECnAEEy",21 "dataType": "DATA_HASH",22 "metadataHash": "DU1sYzPcRnvAUL6VzerhAmDQUyrn4UceAvV4K6WtZxBi",23 "payments": []24}
PUBLISH_MULTIPLE_QDN_RESOURCES
1const resourceArray = [2 {3 name: "Demo",4 service: "IMAGE",5 identifier: "myapp-image1"6 file: "file_object",7 filename: "image1.png"8 },9 {10 name: "Demo",11 service: "IMAGE",12 identifier: "myapp-image2"13 file: "file_object",14 filename: "image2.png"15 }16]17const response = await qortalRequest({18 action: 'PUBLISH_MULTIPLE_QDN_RESOURCES',19 resources: resourceArray20})
RESPONSE
1[2 {3 "type": "ARBITRARY",4 "timestamp": 1684337616751,5 "reference": "4j2iPN5Xwgocs8Z32JB4UB63G87qS43kPyEwFmQMLvWBXtrSQwAfyx8S9CqQvbregnstXFKqXpkPT2dNdAscriT4",6 "fee": "0.00100000",7 "signature": "5Y6Jdyvo8n6JB44qC8i57x2gA3VXd7aah42GvnzkXL459vCWrRE5gae5TWbGqJxmKnk4p5ESHESv2FJfyB8bdzs9",8 "txGroupId": 0,9 "approvalStatus": "NOT_REQUIRED",10 "creatorAddress": "QMjCNsctvWLoDdPSRpHn6TF2j96iDr9YWm",11 "version": 5,12 "senderPublicKey": "Bjo1iUHJXbCb4LKabmE6KWNL5jSgCK36ypasoDgJG53U",13 "service": 777,14 "nonce": 0,15 "size": 496,16 "name": "Demo",17 "identifier": "myapp-image1",18 "method": "PUT",19 "secret": "GELP1wMCyMAcwLWTvsAjsFoiR63BcAF7wmrhd1NVhjL",20 "compression": "ZIP",21 "data": "ArzaQASrXM74SDhWp6JhhmUBsocWRoVajZFtYECnAEEy",22 "dataType": "DATA_HASH",23 "metadataHash": "DU1sYzPcRnvAUL6VzerhAmDQUyrn4UceAvV4K6WtZxBi",24 "payments": []25 },26 {27 "type": "ARBITRARY",28 "timestamp": 1684337616751,29 "reference": "4j2iPN5Xwgocs8Z32JB4UB63G87qS43kPyEwFmQMLvWBXtrSQwAfyx8S9CqQvbregnstXFKqXpkPT2dNdAscriT4",30 "fee": "0.00100000",31 "signature": "5Y6Jdyvo8n6JB44qC8i57x2gA3VXd7aah42GvnzkXL459vCWrRE5gae5TWbGqJxmKnk4p5ESHESv2FJfyB8bdzs9",32 "txGroupId": 0,33 "approvalStatus": "NOT_REQUIRED",34 "creatorAddress": "QMjCNsctvWLoDdPSRpHn6TF2j96iDr9YWm",35 "version": 5,36 "senderPublicKey": "Bjo1iUHJXbCb4LKabmE6KWNL5jSgCK36ypasoDgJG53U",37 "service": 777,38 "nonce": 0,39 "size": 496,40 "name": "Demo",41 "identifier": "myapp-image2",42 "method": "PUT",43 "secret": "GELP1wMCyMAcwLWTvsAjsFoiR63BcAF7wmrhd1NVhjL",44 "compression": "ZIP",45 "data": "ArzaQASrXM74SDhWp6JhhmUBsocWRoVajZFtYECnAEEy",46 "dataType": "DATA_HASH",47 "metadataHash": "DU1sYzPcRnvAUL6VzerhAmDQUyrn4UceAvV4K6WtZxBi",48 "payments": []49 }50]
SAVE_FILE
This action requires user approval
1await qortalRequest({2 action: "SAVE_FILE",3 blob: dataBlob,4 filename: "myfile.pdf",5 mimeType: "application/pdf" // Optional but recommended6});
SEARCH_NAMES
Equivalent to: /names/search?query=qortal&limit=20
1const response = await qortalRequest({2 action: "SEARCH_NAMES",3 query: "search query goes here",4 prefix: false, // Optional - if true, only the beginning of the name is matched5 limit: 100,6 offset: 0,7 reverse: false8})
RESPONSE
1[2 {3 "name": "... Playing Qortal ...",4 "reducedName": "... p1aying q0rta1 ...",5 "owner": "QNwKEgYaJzF7MTZzFMJUnQgkemiac18bf6",6 "data": "The most interactive game in the World!",7 "registered": 1644330871648,8 "isForSale": false9 },10 {11 "name": "10Qortal",12 "reducedName": "10q0rta1",13 "owner": "QhLt2v3TDJrBPCa64ogUna785T6sRm5dxJ",14 "data": "Registered Name on the Qortal Chain",15 "registered": 1644995489154,16 "isForSale": false17 },18]
SEARCH_QDN_RESOURCES
Equivalent to: /arbitrary/resources/search?
1const response = await qortalRequest({2 action: "SEARCH_QDN_RESOURCES",3 service: "THUMBNAIL",4 query: "search query goes here", // Optional - searches both "identifier" and "name" fields5 identifier: "search query goes here", // Optional - searches only the "identifier" field6 name: "search query goes here", // Optional - searches only the "name" field7 prefix: false, // Optional - if true, only the beginning of fields are matched in all of the above filters8 exactMatchNames: true, // Optional - if true, partial name matches are excluded9 default: false, // Optional - if true, only resources without identifiers are returned10 includeStatus: false, // Optional - will take time to respond, so only request if necessary11 includeMetadata: false, // Optional - will take time to respond, so only request if necessary12 nameListFilter: "QApp1234Subscriptions", // Optional - will only return results if they are from a name included in supplied list13 followedOnly: false, // Optional - include followed names only14 excludeBlocked: false, // Optional - exclude blocked content15 limit: 100,16 offset: 0,17 reverse: true18});
RESPONSE
1[2 // with includemetadata:true3 {4 "name": "Q-Blog",5 "service": "BLOG_POST",6 "identifier": "q-blog-qblog-post-Publishing-Blog-s-SncAO3",7 "metadata": {8 "title": "Publishing Blog Posts",9 "description": "Learn how to publish blog posts. There are two types of editors. Find out which one is for you!",10 "tags": [11 "v1.0x0",12 "t, v"13 ],14 "mimeType": "text/vnd.graphviz"15 },16 "size": 928,17 "created": 1682190828187,18 "updated": 168220017208619 },20 // without includemetadata21 {22 "name": "Q-Blog",23 "service": "BLOG_POST",24 "identifier": "q-blog-qblog-post-Publishing-Blog-s-SncAO3",25 "size": 928,26 "created": 1682190828187,27 "updated": 168220017208628 },29]
SEARCH_CHAT_MESSAGES
Equivalent to: /chat/messages?
This action requires user approval
1const response = await qortalRequest({2 action: "SEARCH_CHAT_MESSAGES",3 before: 999999999999999,4 after: 0,5 txGroupId: 0, // Optional (must specify either txGroupId or two involving addresses)6 // involving: ["QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2", "QSefrppsDCsZebcwrqiM1gNbWq7YMDXtG2"], // Optional (must specify either txGroupId or two involving addresses)7 // reference: "reference", // Optional8 // chatReference: "chatreference", // Optional9 // hasChatReference: true, // Optional10 encoding: "BASE64", // Optional (defaults to BASE58 if omitted)11 limit: 20,12 offset: 0,13 reverse: true14});
RESPONSE
1[2 {3 "timestamp": 1684326780846,4 "txGroupId": 0,5 "reference": "BRr2qZEts2QjoGh9fWGNSnKJiCr92vXDBw9aPYYKNDFq4iSxtFpBnh7giJK5jiP5YGNQTbySu3kSnHGZbHf6HL9",6 "senderPublicKey": "HpFimVDQeSb3yCaibrpLLfm8k5j3RsQ9K8VqT2YUiUAb",7 "sender": "QfMPvGEBJMhhNSfhNqRy6qRYvybdnQAiuJ",8 "senderName": "Stonecrow",9 "encoding": "BASE64",10 "data": "eyJtZXNzYWdlVGV4dCI6eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6InBhcmFncmFwaCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6Imdvb2RuaWdodCBDYXQuwqAgQmFjayBpbiB5dXIgYm94IG5vdy4gVGhhdCBuYXN0eSB0cmVlIHdvbnQgYm90aGVyIHlvdSBubyBtb3JlLiJ9XX1dfSwiaW1hZ2VzIjpbIiJdLCJyZXBsaWVkVG8iOiIiLCJ2ZXJzaW9uIjozfQ==",11 "isText": true,12 "isEncrypted": false,13 "signature": "4ja9XuNReuhn1Gh7uPvZXxZZnFVxXejvRFphQUZNC2FRqWn3Jv9T8oXnU6dxoGTSeYhiW8GUzkqmHZFaFLFibFWd"14 },15 {16 "timestamp": 1684326755079,17 "txGroupId": 0,18 "reference": "5o8YcSvPEY2yV6o8DxQcQgK9tAdHjncT4K6n1oXeJo51yUEXxQ9doMrFRnaVEb3QHZmAtvcWDkd1fojqcuNWbDcP",19 "senderPublicKey": "AKLvYPJLqJTVovRThNu33vfhWTPFPZH5DpjguiNAacvG",20 "sender": "QfKKzGktu6FzNGWrzxcmVJZ3SJV53PMtTw",21 "senderName": "Dreaming_Loudly",22 "encoding": "BASE64",23 "data": "eyJtZXNzYWdlVGV4dCI6eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6InBhcmFncmFwaCIsImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6Ikh1cnJ5IHVwIC0gSSdtIGdldHRpbmcgY29sZCBseWluZyBoZXJlIC3CoPCfmJsifV19XX0sImltYWdlcyI6WyIiXSwicmVwbGllZFRvIjoiNDRTODhIZ0hqcUJ1RnF5WkNyaDMxUGdkWUZhWEpaVzFTWlZlempEVVprdHg3WWZ1Q0RvWXZOOWRzWVNvUVM4cTlWRE43eFpMeGNHSzV3RUoxNndLdTJSbyIsInZlcnNpb24iOjN9",24 "isText": true,25 "isEncrypted": false,26 "signature": "3qFMqF2P1Xy6bAEHmcqKbxMu4zRyVfbGf87mBrBNAcyw9hYpAa3A1dYzMjbBdWMQQNBBugzQHpsy246CrnoYRuoc"27 },28 ...29]
SEARCH_TRANSACTIONS
Equivalent to: /transactions/search?
1const response = await qortalRequest({2 action: "SEARCH_TRANSACTIONS",3 // startBlock: 1139000,4 // blockLimit: 1000,5 txGroupId: 0,6 txType: [7 "PAYMENT",8 "REWARD_SHARE"9 ],10 confirmationStatus: "CONFIRMED",11 limit: 10,12 offset: 0,13 reverse: false14});
RESPONSE
1[23 {4 "type": "PAYMENT",5 "timestamp": 1593450783307,6 "reference": "TvFaY9C3CPuNwNeE2HthKCbu3BtRhqSNaQ2UuuaobphfErasiVAnKcU8aFyeRiTi8B3rgiNVZMzWWWh48y155Gk",7 "fee": "0.00100000",8 "signature": "5kMSsag5nj4YqNrz7kQ3inQ1xjoC6vc2Z8Trhiz2Yi8okShATP43qRkMaFhDUAXpSKDQd8xEXuWvMzXER4BQLFRx",9 "txGroupId": 0,10 "blockHeight": 14,11 "approvalStatus": "NOT_REQUIRED",12 "creatorAddress": "QfmM8dgfikTB2FYVuJ9owzQXVm8wP7T4QT",13 "senderPublicKey": "7YfqZ1xWFnDWTThUG1uRYK3CX1vb4mNCH8gvqtH2VCeg",14 "recipient": "QRFHr4jnVgvAsPTubeSrh8bPy1yzwzYaWD",15 "amount": "0.01000000"16 },17 {18 "type": "PAYMENT",19 "timestamp": 1593453009886,20 "reference": "4FF6ADq3hqsw2HpbhSdr56LvyZj9yfQLVSztKxaEGc8DvMZWZD5c5B3nR7jzC9MzzsNeqMdauV6q7ZnKm6DUqBMm",21 "fee": "0.00100000",22 "signature": "5kioTqM1C4gyRnBLEPx76V67bHGuW7t4YEZRZwg3HnKkpHvF2h4vx9uUwRNiJR1NPAEp5GWMDKsAsi7GP9LbozNM",23 "txGroupId": 0,24 "blockHeight": 50,25 "approvalStatus": "NOT_REQUIRED",26 "creatorAddress": "Qi3N6fNRrs15EHmkxYyWHyh4z3Dp2rVU2i",27 "senderPublicKey": "HmViWJ2SMRVTYNuMvNYFBX7DitXcEB2gBZasAN3uheJL",28 "recipient": "QPFM4xX2826MuBEhMtdReW1QR3vRYrQff3",29 "amount": "1.00000000"30 },31 ...32]
SEND_CHAT_MESSAGE
Send a group chat message
This action requires user approval
1const response = await qortalRequest({2 action: "SEND_CHAT_MESSAGE",3 groupId: 0,4 message: "Test"5});
RESPONSE
1true
Send a private chat message
1const response = await qortalRequest({2 action: "SEND_CHAT_MESSAGE",3 destinationAddress: "QZLJV7wbaFyxaoZQsjm6rb9MWMiDzWsqM2",4 message: "Test"5});
RESPONSE
1true
SEND_COIN
Send QORT to address
This action requires user approval
1const response = await qortalRequest({2 action: "SEND_COIN",3 coin: "QORT",4 destinationAddress: "Qi3x7zVhN17mcYm9JTrEYaFihmETSZTzPD",5 amount: 1.00000000 // 1 QORT6});
RESPONSE
1{2 amount: '1.00000000'3 approvalStatus: 'NOT_REQUIRED'4 creatorAddress: 'QMjCNsctvWLoDdPSRpHn6TF2j96iDr9YWm'5 fee: '0.00100000'6 recipient: 'Qi3x7zVhN17mcYm9JTrEYaFihmETSZTzPD'7 reference: '26xJXTxcdXhFUYFkyZ7qKkj94RtaLBevcyQgCwK3W5xt7JkGPrCbvNgdC46CmJA65cjTCXMykwiyYJfVsPdsU1fS'8 senderPublicKey: 'Bjo1iUHJXbCb4LKabmE6KWNL5jSgCK36ypasoDgJG53U'9 signature: '4j2iPN5Xwgocs8Z32JB4UB63G87qS43kPyEwFmQMLvWBXtrSQwAfyx8S9CqQvbregnstXFKqXpkPT2dNdAscriT4'10 timestamp: 168432131052211 txGroupId: 012 type: 'PAYMENT'13}
Send foreign coin to address
1const response = await qortalRequest({2 action: "SEND_COIN",3 coin: "LTC",4 destinationAddress: "LSdTvMHRm8sScqwCi6x9wzYQae8JeZhx6y",5 amount: 1.00000000, // 1 LTC6});
SEND_LOCAL_NOTIFICATION
Send a notification to the user from your Q-App
1const response = await qortalRequest({2 action: 'SEND_LOCAL_NOTIFICATION',3 qortalLink: 'qortal://APP/Ear-Bump/liked',4 title: 'hello testing',5 url: "qortal://APP/Q-Blog",6 message: 'this is the body message',7 icon: "data:image/gif;base64,R0lGODlhPQBEAPeoAJosM//AwO/AwHVYZ/z595kzAP/s7P+goOXMv8+fhw/v739/f+8PD98fH/8mJl+fn/9ZWb8/PzWlwv///6wWGbImAPgTEMImIN9gUFCEm/gDALULDN8PAD6atYdCTX9gUNKlj8wZAKUsAOzZz+UMAOsJAP/Z2ccMDA8PD/95eX5NWvsJCOVNQPtfX/8zM8+QePLl38MGBr8JCP+zs9myn/8GBqwpAP/GxgwJCPny78lzYLgjAJ8vAP9fX/+MjMUcAN8zM/9wcM8ZGcATEL+QePdZWf/29uc/P9cmJu9MTDImIN+/r7+/vz8/P8VNQGNugV8AAF9fX8swMNgTAFlDOICAgPNSUnNWSMQ5MBAQEJE3QPIGAM9AQMqGcG9vb6MhJsEdGM8vLx8fH98AANIWAMuQeL8fABkTEPPQ0OM5OSYdGFl5jo+Pj/+pqcsTE78wMFNGQLYmID4dGPvd3UBAQJmTkP+8vH9QUK+vr8ZWSHpzcJMmILdwcLOGcHRQUHxwcK9PT9DQ0O/v70w5MLypoG8wKOuwsP/g4P/Q0IcwKEswKMl8aJ9fX2xjdOtGRs/Pz+Dg4GImIP8gIH0....."8})
RESPONSE
1true
SET_PROFILE_DATA
This action requires user approval
Sets a custom property in the user's profile. The custom property will be a key-value pair object that will have a custom property name. There can be more than one key-value pair per object for every custom property.
We call this within a qortalRequestWithTimeout function because we want to wait for the user to navigate and check the auto-filled info in their profile before updating their profile with the new data.
Set a normal custom property
1const summary = await qortalRequestWithTimeout({2 action: "SET_PROFILE_DATA",3 property: "foo",4 data: {5 customData: {6 newKey: "bar"7 }8 }9}, 30000);
RESPONSE
1"saved"
The user can had a "-private" suffix to the property name to make it private. This will make the property encrypted, meaning that Q-Apps will require user approval to access that specific property.
Set a private custom property
1const summary = await qortalRequestWithTimeout({2 action: "SET_PROFILE_DATA",3 property: "fruits-private",4 data: {5 customData: {6 berries: "strawberries",7 }8 }9}, 30000);
RESPONSE
1"saved"
VOTE_ON_POLL
Vote on a previously created poll. If the poll name doesn't exist, it will throw an error.
This action requires user approval
1await qortalRequest({2 action: "VOTE_ON_POLL",3 pollName: "A test poll 3",4 optionIndex: 1,5});
RESPONSE
1{2 "type": "VOTE_ON_POLL",3 "timestamp": 1697286687406,4 "reference": "3jU9WpEPAvu9iL3cMfVd2AUmn9AijJRzkGCxVtXfpuUFZubM8AFDcbk5XA9m5AhPfsbMDFkSDzPJnkjeLA5GA59E",5 "fee": "0.01000000",6 "signature": "3QJ1EUvX3rskVNaP3RWvJwb9DsGgHPvneWqBWS62PCcuCj5N4Ei9Tr4nFj4nQeMqMU2qNkVD3Sb59e7iUWkawH3s",7 "txGroupId": 0,8 "approvalStatus": "NOT_REQUIRED",9 "creatorAddress": "Qhxphh7g5iNtxAyLLpPMZzp4X85yf2tVam",10 "voterPublicKey": "C5spuNU1BAHZDEkxF3wnrAPRDuNrVceaDJ6tDKitenko",11 "pollName": "A test poll 3",12 "optionIndex": 113}