App-controlled, embedded wallets for a smooth UX
Overview
You'll find API endpoints and key usage notes below. If you ever need help with an integration question, you can reach out to us.
Use Cases
Shinami’s Invisible Wallets abstract away Web3 elements like seed phrases, third-party wallet connections, gas fees, and signing popups. They are embedded, backend wallets under the shared custody of your app and Shinami. Both parties must cooperate in order to obtain a valid signature.
Shinami Gas Station Integration
All methods below that write to the Aptos blockchain have their gas fees sponsored by you via a Gas Station fund you create. This is because Invisible Wallets are designed to easily onboard Web2-native users (who may not want to download a wallet app, manage a seed phrase, and complete KYC checks to buy APT for gas). See the Aptos Gas Station FAQ page in our Help Center for how guidance on how to set up a fund.
Authentication, Rate Limits, and Error Handling
Authentication
You authenticate via an access key passed in a header ('X-Api-Key: ACCESS_KEY') or in the request url (https://api.shinami.com/aptos/wallet/v1/ACCESS_KEY
). We recommend using a request header and not putting access keys in your request URLs for reduced visibility (in logs, etc). These steps are done automatically by our TypeScript SDK.
See our Authentication and API Keys guide for how to set up a Wallet-Services-only access key and an access key with Wallet Services and Gas Station rights (needed to execute transactions and initialize Invisible Wallets on chain).
Call this API from your backend
Shinami Wallet Services do not support CORS requests, so if you make requests to these APIs from your frontend you'll get a CORS error. This is for security reasons: exposed keys and wallet information could lead to malicious actors signing transactions on behalf of your users.
Rate Limits
When you surpass the QPS limit for a key, we return a JSON-RPC error code -32010
. We recommend implementing retries with a backoff to handle any rate limits errors that arise. You can also adjust the rate limits of your keys to better balance your QPS allotment across your keys.
Error Handling
See our Error Reference for guidance on the errors you may receive from our services, including a section on errors specific to the Invisible Wallet API.
WalletId and Secret Pairing
When you create an Invisible Wallet, you must create, store, link, and never change the following two values:
walletId
: Your internal id for a wallet. When you provide us awalletId
in a method call, it tells us which Invisible Wallet to use. It could be your internaluserId
value, or a new arbitrary and unique value you link to theuserId
.secret
: Your internal secret for a wallet. ThesessionToken
you generate with it is combined with Shinami data to obtain a signature from the associated wallet. Ideally it would be different for each wallet so that if onesecret
is compromised the rest are not.
When you create an Invisible Wallet, you forever link its walletId it to the secret you used:
So, if you try to use the walletId with a different secret, you'll get an error:
Methods
shinami_key_createSession
Description
For security purposes, you must generate a session token before you create a wallet, or sign/execute transactions. Session tokens are valid and can be reused for 10 minutes.
You may also use an instance of ShinamiWalletSigner
to manage session token generation and refreshes for a given wallet. This is shown in the methods below that have a sessionToken
parameter in an additional sample code tab.
Request Parameters
Name | Type | Description |
---|---|---|
secret | string | Used to encrypt and decrypt a wallet's private key. Therefore, it must always be used with the same walletId and cannot be changed in the future (see walletId and secret pairing) |
Example Request Template
The TypeScript example uses the Shinami Clients SDK.
Replace all instances of {{name}}
with the actual value for that name
curl https://api.shinami.com/aptos/key/v1 \
-X POST \
-H 'X-API-Key: {{walletServicesAccessKey}}' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"method":"key_createSession",
"params":[
"{{secret}}"
],
"id":1
}'
import { KeyClient } from "@shinami/clients/aptos";
const keyClient = new KeyClient({{walletServicesAccessKey}});
await keyClient.createSession({{secret}});
Example Response
{
"jsonrpc":"2.0",
"result":"eyJraWQiOiJrZXkyMDIzMDgxMSIsImVuYyI6IkEyNTZHQ00iLCJ0YWciOiI4SVpQWXlHeDlmOTd6U2NIdmN6N3lnIiwiYWxnIjoiQTI1NkdDTUtXIiwiaXYiOiJQWVJXZFJrbnNMMlNnVzhfIn0.ygDCI-NcvUcH7wYc0Bp0-59qeIfGOqLyXZGsLF4pW0M.aOAW0AwBvAWpaS-S.QmesdNIdNIYbT59RET-lNuzNMUvS-xb2exhXrAIlspnIkV3nuBx7PKC_GgJ7C1EqJx3tDtQaLLDGdrO8_s-75oK88ls5mzDRR-w2A0VdCcTH0_JwsQgijIbCKFWS0g.dULMzxZ4gGbm2unqOnzv8w",
"id": 1
}
"eyJraWQiOiJrZXkyMDIzMDgxMSIsImVuYyI6IkEyNTZHQ00iLCJ0YWciOiI4SVpQWXlHeDlmOTd6U2NIdmN6N3lnIiwiYWxnIjoiQTI1NkdDTUtXIiwiaXYiOiJQWVJXZFJrbnNMMlNnVzhfIn0.ygDCI-NcvUcH7wYc0Bp0-59qeIfGOqLyXZGsLF4pW0M.aOAW0AwBvAWpaS-S.QmesdNIdNIYbT59RET-lNuzNMUvS-xb2exhXrAIlspnIkV3nuBx7PKC_GgJ7C1EqJx3tDtQaLLDGdrO8_s-75oK88ls5mzDRR-w2A0VdCcTH0_JwsQgijIbCKFWS0g.dULMzxZ4gGbm2unqOnzv8w"
Response Data
Type | Description |
---|---|
string | sessionToken corresponding to the provided secret . Valid and can be reused for 10 minutes. |
wal_createWallet
Description
Creates a new Shinami invisible wallet, but not yet initialized on the Aptos chain.
Request Parameters
Name | Type | Description |
---|---|---|
walletId | string | A unique ID you maintain for the wallet. Can be based on your internal user IDs. Note: you cannot change this value in the future, so do not use a value that you or your users might change, such as a editable username. |
sessionToken | string | The token generated by shinami_key_createSession with the unalterable secret you will permanently associate with this walletId (and, ideally, only this walletId). |
Example Request Template
The TypeScript example uses the Shinami Clients SDK.
Replace all instances of {{name}}
with the actual value for that name
curl https://api.shinami.com/aptos/wallet/v1 \
-X POST \
-H 'X-API-Key: {{walletServicesAccessKey}}' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"method": "wal_createWallet",
"params": [
"{{walletId}}",
"{{sessionToken}}"
],
"id": 1
}'
import { KeyClient, WalletClient } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}}";
const keyClient = new KeyClient({{walletServicesAccessKey}});
let sessionToken = await keyClient.createSession({{walletSecret}});
await walletClient.createWallet(
{{walletID}},
sessionToken
);
import { WalletClient, KeyClient, ShinamiWalletSigner } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
const signer = new ShinamiWalletSigner(
{{walletId}},
walletClient,
{{walletSecret}},
keyClient
);
// Return the Aptos wallet address associated with the
// walletId, or create an Invisible Wallet tied to that
// walletId if none is found and return its address.
const CREATE_WALLET_IF_NOT_FOUND = true;
const INITIALIZE_ON_CHAIN_IF_CREATING = false;
let walletAddress = await signer.getAddress(
CREATE_WALLET_IF_NOT_FOUND,
INITIALIZE_ON_CHAIN_IF_CREATING
);
Example Response
{
"id" : 1,
"jsonrpc" : "2.0",
"result" : {
"accountAddress" : "0x45329e69bf823b556ab930a244ab33e0a71f4065d52b4a763e51af2f4b4d214a"
}
}
AccountAddress: https://github.com/aptos-labs/aptos-ts-sdk/blob/28803638e61a6eac877924cb6b0903df77e5842f/src/core/accountAddress.ts#L42
AccountAddress: https://github.com/aptos-labs/aptos-ts-sdk/blob/28803638e61a6eac877924cb6b0903df77e5842f/src/core/accountAddress.ts#L42
Response Fields
An object with the following keys:
Name | Type | Description |
---|---|---|
accountAddress | cURL string SDK AccountAddress | The Aptos address of created wallet. |
wal_initializeWalletOnChain
Description
Initializes a Shinami Invisible Wallet on the Aptos network the Gas Station rights of your access key is associated with. This comes after a call to wal_createWallet
but is not always needed. That's because initialization happens automatically if you send a transaction with an uninitialized wallet (e.g. calling wal_executeGaslessTransaction
). We provide this method to give you flexibility.
Access Key Requirements: In addition to Wallet Services rights, making this request requires an access key with Node Service and Gas Station rights for the Aptos network you wish to initialize the wallet on. This is because initialization involves submitting a basic transaction with the Invisible Wallet as the sender and the gas fee sponsored by your Gas Station fund. See how to make one here. See also the next section:
Gas Station fund required: You need a Gas Station fund with APT in order to sponsorship transactions for an Invisible Wallet, including the transaction that explicitly initializes it on chain. For information on how to set this up, see the Aptos Gas Station FAQ page in our Help Center.
Shinami sponsorship fees: See our Aptos Billing FAQ.
Request Parameters
Name | Type | Description |
---|---|---|
walletId | string | A unique ID you maintain for the wallet. Can be based on your internal user IDs. Note: you cannot change this value in the future, so do not use a value that you or your users might change, such as a editable username. |
sessionToken | string | The token generated by shinami_key_createSession with the unalterable secret you will permanently associate with this walletId (and, ideally, only this walletId). |
Example Request Template
The TypeScript example uses the Shinami Clients SDK.
Replace all instances of {{name}}
with the actual value for that name
curl https://api.shinami.com/aptos/wallet/v1 \
-X POST \
-H 'X-API-Key: {{walletServicesAccessKey}}' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"method": "wal_initializeWalletOnChain",
"params": [
"{{walletId}}",
"{{sessionToken}}"
],
"id": 1
}'
import { KeyClient, WalletClien } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
let sessionToken = await keyClient.createSession({{walletSecret}});
await walletClient.initializeWalletOnChain(
{{walletID}},
sessionToken
);
import { WalletClient, KeyClient, ShinamiWalletSigner } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
const signer = new ShinamiWalletSigner(
{{walletId}},
walletClient,
{{walletSecret}},
keyClient
);
// Return the Aptos wallet address associated with the
// walletId, or create an Invisible Wallet tied to that
// walletId if none is found and return its address.
// Initialize it on the network the access key's Gas
// Station rights are associated with.
const CREATE_WALLET_IF_NOT_FOUND = true;
const INITIALIZE_ON_CHAIN_IF_CREATING = true;
let walletAddress = await signer.getAddress(
CREATE_WALLET_IF_NOT_FOUND,
INITIALIZE_ON_CHAIN_IF_CREATING
);
Example Response
{
"id" : 1,
"jsonrpc" : "2.0",
"result" : {
"accountAddress" : "0x45329e69bf823b556ab930a244ab33e0a71f4065d52b4a763e51af2f4b4d214a"
}
}
AccountAddress: https://github.com/aptos-labs/aptos-ts-sdk/blob/28803638e61a6eac877924cb6b0903df77e5842f/src/core/accountAddress.ts#L42
AccountAddress: https://github.com/aptos-labs/aptos-ts-sdk/blob/28803638e61a6eac877924cb6b0903df77e5842f/src/core/accountAddress.ts#L42
Response Fields
An object with the following keys:
Name | Type | Description |
---|---|---|
accountAddress | cURL string SDK AccountAddress | The Aptos address of created wallet. |
wal_createWalletOnChain
Description
Creates and initializes a Shinami invisible wallet onto the Aptos chain.
Access Key Requirements: In addition to Wallet Services rights, making this request requires an access key with Node Service rights and Gas Station rights for the Aptos network you wish to initialize the wallet on. This is because initialization involves submitting a basic transaction with the Invisible Wallet as the sender and the gas fee sponsored by your Gas Station fund. See how to make one here. See also the next section:
Gas Station fund required: You need a Gas Station fund with APT in order to sponsorship transactions for an Invisible Wallet, including the transaction that explicitly initializes it on chain. For information on how to set this up, see the Aptos Gas Station FAQ page in our Help Center.
Shinami sponsorship fees: See our Aptos Billing FAQ.
Request Parameters
Name | Type | Description |
---|---|---|
walletId | string | A unique ID you maintain for the wallet. Can be based on your internal user IDs. Note: you cannot change this value in the future, so do not use a value that you or your users might change, such as a editable username. |
sessionToken | string | The token generated by shinami_key_createSession with the unalterable secret you will permanently associate with this walletId (and, ideally, only this walletId). |
Example Request Template
The TypeScript example uses the Shinami Clients SDK.
Replace all instances of {{name}}
with the actual value for that name
curl https://api.shinami.com/aptos/wallet/v1 \
-X POST \
-H 'X-API-Key: {{walletServicesAccessKey}}' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"method": "wal_createWalletOnChain",
"params": [
"{{walletId}}",
"{{sessionToken}}"
],
"id": 1
}'
import { KeyClient, WalletClien } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
let sessionToken = await keyClient.createSession({{walletSecret}});
await walletClient.createWalletOnChain(
"{{walletID}}",
sessionToken
);
import { WalletClient, KeyClient, ShinamiWalletSigner } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
const signer = new ShinamiWalletSigner(
{{walletId}},
walletClient,
{{walletSecret}},
keyClient
);
// Return the Aptos wallet address associated with the
// walletId, or create an Invisible Wallet tied to that
// walletId if none is found and return its address.
// Initialize it on the network the access key's Gas
// Station rights are associated with.
const CREATE_WALLET_IF_NOT_FOUND = true;
const INITIALIZE_ON_CHAIN_IF_CREATING = true;
let walletAddress = await signer.getAddress(
CREATE_WALLET_IF_NOT_FOUND,
INITIALIZE_ON_CHAIN_IF_CREATING
);
Example Response
{
"id" : 1,
"jsonrpc" : "2.0",
"result" : {
"accountAddress" : "0x45329e69bf823b556ab930a244ab33e0a71f4065d52b4a763e51af2f4b4d214a"
}
}
AccountAddress: https://github.com/aptos-labs/aptos-ts-sdk/blob/28803638e61a6eac877924cb6b0903df77e5842f/src/core/accountAddress.ts#L42
AccountAddress: https://github.com/aptos-labs/aptos-ts-sdk/blob/28803638e61a6eac877924cb6b0903df77e5842f/src/core/accountAddress.ts#L42
Response Fields
An object with the following keys:
Name | Type | Description |
---|---|---|
accountAddress | cURL string SDK AccountAddress | The Aptos address of created wallet. |
wal_getWallet
Description
Gets the address of an existing wallet, regardless of whether it is initialized or uninitialized on chain.
Request Parameters
Name | Type | Description |
---|---|---|
walletId | string | A unique ID you maintain for the wallet. Can be based on your internal user IDs. Note: you cannot change this value in the future, so do not use a value that you or your users might change, such as a editable username. |
Example Request Template
The TypeScript example uses the Shinami Clients SDK.
Replace all instances of {{name}}
with the actual value for that name
curl https://api.shinami.com/aptos/wallet/v1 \
-X POST \
-H 'X-API-Key: {{walletServicesAccessKey}}' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"method": "wal_getWallet",
"params": [
"{{walletId}}"
],
"id": 1
}'
import { KeyClient, WalletClien } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
let sessionToken = await keyClient.createSession({{walletSecret}});
await walletClient.getWallet(
{{walletID}}
);
import { WalletClient, KeyClient, ShinamiWalletSigner } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}}";
const keyClient = new KeyClient({{walletServicesAccessKey}});
const signer = new ShinamiWalletSigner(
{{walletId}},
walletClient,
{{walletSecret}},
keyClient
);
await signer.getAddress();
Example Response
{
"id" : 1,
"jsonrpc" : "2.0",
"result" : {
"accountAddress" : "0x45329e69bf823b556ab930a244ab33e0a71f4065d52b4a763e51af2f4b4d214a"
}
}
AccountAddress: https://github.com/aptos-labs/aptos-ts-sdk/blob/28803638e61a6eac877924cb6b0903df77e5842f/src/core/accountAddress.ts#L42
AccountAddress: https://github.com/aptos-labs/aptos-ts-sdk/blob/28803638e61a6eac877924cb6b0903df77e5842f/src/core/accountAddress.ts#L42
Response Fields
An object with the following keys:
Name | Type | Description |
---|---|---|
accountAddress | cURL string SDK AccountAddress | The Aptos address of created wallet. |
wal_signTransaction
Description
Use an initialized Shinami Invisible Wallet to sign a transaction. When the wallet is the sender and you are sponsoring as the feePayer, use wal_executeGaslessTransaction
, which does all of: sign, sponsor, and submit the transaction to the Aptos network.
Notes:
- The Invisible wallet must be initialized on chain in order to sign.
- If you attempt to sign immediately after initializing a wallet you may get an error that the address was not found on chain, as it take a couple of seconds for the initialization to be processed by the Aptos blockchain.
Request Parameters
Name | Type | Description |
---|---|---|
walletId | string | A unique ID you maintain for the wallet. Can be based on your internal user IDs. Note: you cannot change this value in the future, so do not use a value that you or your users might change, such as a editable username. |
sessionToken | string | The token generated by shinami_key_createSession with the unalterable secret you will permanently associate with this walletId (and, ideally, only this walletId). |
SDK-only transaction | AnyRawTransaction | A SimpleTransaction or a MultiAgentTransaction that does not have a fee payer. You can find an example of building a transaction in our tutorial |
cURL-only rawTransaction | Hex string | unsigned byte array | BCS-serialized RawTransaction. Can be passed either as an unsigned byte array or a Hex string. For a Python example of how to serialize this to send to Shinami, see the Aptos Python SDK: rawTransaction tab of the Example Request Templates. |
cURL-only secondaryAddresses | string[] | (Optional) Required for multi-agent transactions. Array of addresses of the secondary signers for the transaction. Must be in the exact order. |
cURL-only feePayerAddress | string | (Optional) Address of a feepayer for the rawTransaction. |
Example Request Template
The TypeScript example uses the Shinami Clients SDK.
Replace all instances of {{name}}
with the actual value for that name
curl https://api.shinami.com/aptos/wallet/v1 \
-X POST \
-H 'X-API-Key: {{walletServicesAccessKey}}' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"method": "wal_signTransaction",
"params": [
"{{walletId}}",
"{{sessionToken}}",
"{{rawTransaction}}",
"{{(optional)secondardAddresses}}",
"{{(optional)feePayerAddress}}"
],
"id": 1
}'
import { KeyClient, WalletClien } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
let sessionToken = await keyClient.createSession({{walletSecret}});
// sign a non-feePayer transaction
await walletClient.signTransaction(
{{walletID}},
sessionToken,
{{transaction}}
);
import { WalletClient, KeyClient, ShinamiWalletSigner } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
const signer = new ShinamiWalletSigner(
{{walletId}},
walletClient,
{{walletSecret}},
keyClient
);
// sign a non-feePayer transaction
await signer.signTransaction({{transaction}});
# Here is an example of preparing a `RawTransaction` to be sent
# as the `rawTransaction` parameter
from aptos_sdk.bcs import Serializer
...
# Step 1:
# Build your RawTransaction with your Invisible Wallet address as the
# sender address. Below, we represent your RawTransaction
# with the variable `raw_transaction`
# Step 2:
# Prepare your RawTransaction to send to Shinami's API.
# Two options are shown below
# Option 1: send as an unsigned byte array
shinami_rawTransaction = list(raw_transaction.to_bytes())
# Option 2: send as a hex string
transaction_serializer = Serializer()
raw_transaction.serialize(transaction_serializer)
shinami_rawTransaction = transaction_serializer.output().hex()
Example Response
{
"jsonrpc":"2.0",
"result":{
"signature":[0,32,136,128,248,41,24,171,70,49,247,26,7,233,63,120,178,130,84,171,58,188,184,203,137,23,210,92,89,62,182,10,55,2,64,239,224,55,68,196,84,93,88,60,245,168,112,48,199,204,225,105,109,15,6,64,145,58,175,225,89,230,38,71,179,223,193,212,114,240,142,212,165,123,209,71,50,202,29,114,133,212,40,240,123,38,189,76,4,208,237,156,135,159,154,143,122,206,9]
,
"id":1
}
AccountAuthenticator: https://github.com/aptos-labs/aptos-core/blob/4045f57eb4b1fe2d055263d0c541f0ca76d1df42/types/src/transaction/authenticator.rs#L488-L506
AccountAuthenticator: https://github.com/aptos-labs/aptos-core/blob/4045f57eb4b1fe2d055263d0c541f0ca76d1df42/types/src/transaction/authenticator.rs#L488-L506
Response Fields
Object with the following keys:
Name | Type | Description |
---|---|---|
signature | cURL Unsigned byte array SDK AccountAuthenticator | The Invisible Wallet's signature for the transaction. |
wal_executeGaslessTransaction
Description
Sponsors, signs, and executes a gasless transaction from a Shinami invisible wallet. This is a convenient end-to-end method for submitting sponsored transactions to the Aptos chain as opposed to doing all the steps individually.
Access Key Requirements: In addition to Wallet Services rights, making this request requires an access key with Gas Station and Node Service rights for the Aptos network you wish to sponsor and execute the transaction on. See how to make one here. See also the next section:
Gas Station fund required: You need a Gas Station fund with APT in order to sponsorship transactions for an Invisible Wallet. For information on how to set this up, see the Aptos Gas Station FAQ page in our Help Center.
Shinami sponsorship fees: See our Aptos Billing FAQ.
Request Parameters
Name | Type | Description |
---|---|---|
walletId | string | A unique ID you maintain for the wallet. Can be based on your internal user IDs. Note: you cannot change this value in the future, so do not use a value that you or your users might change, such as a editable username. |
sessionToken | string | The token generated by shinami_key_createSession with the unalterable secret you will permanently associate with this walletId (and, ideally, only this walletId). |
SDK-only transaction | AnyRawTransaction | A SimpleTransaction or a MultiAgentTransaction . You can find an example of building a transaction in our tutorial |
cURL-only rawTransaction | Hex string | unsigned byte array | BCS-serialized RawTransaction. Can be passed either as an unsigned byte array or a Hex string. For a Python example of how to serialize this to send to Shinami, see the Aptos Python SDK: rawTransaction tab of the Example Request Templates. |
secondarySigners | SDK AccountAuthenticator[] cURL ["address" : , "signature": (Can be passed either as an unsigned byte array or a hex string.)] | (optional) Array of additional signers and their signatures. Must be in the exact order. Required for multi-agent transactions. |
Example Request Template
The TypeScript example uses the Shinami Clients SDK.
Replace all instances of {{name}}
with the actual value for that name
curl https://api.shinami.com/aptos/wallet/v1 \
-X POST \
-H 'X-API-Key: {{walletServicesAccessKey}}' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"method": "wal_executeGaslessTransaction",
"params": [
"{{walletId}}",
"{{sessionToken}}",
"{{rawTransaction}}",
[{
"address": "{{secondarySignerOneAddress}}",
"signature": "{{secondarySignerOneSignature}}"
}]
],
"id": 1
}'
curl https://api.shinami.com/aptos/wallet/v1 \
-X POST \
-H 'X-API-Key: {{walletServicesAccessKey}}' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"method":"wal_executeGaslessTransaction",
"params":[
"{{walletID}}",
"eyJraWQiOiJrZXkyMDI0MDUwMiIsImVuYyI6IkEyNTZHQ00iLCJ0YWciOiIzY1dmODVTQnB1X0VseG5fS19yNTVnIiwiYWxnIjoiQTI1NkdDTUtXIiwiaXYiOiJMdTRxX1Y3aG9fWDdyYXZWIn0.whquEkYQM1GBK3d26VoZNuxCuI1gQMMAA5tGWvPzoGM.mUtlN_sbR9i5rhmX.Ow_jH6bifeciMSxxK49fOLZ5DY3SJ-SnvcYEjmfnJQEIdnbKOOgK7KKjln8QUNgQpIrPtOm5yVNmo8p8Pg60uA7M7a4qBwDHh3_5ffdjAbaW6IYdbfcmDy5ydWrC84nHKLpgSMWHwEltkfE.KnjXE3IAYFX67hycEoH9gQ",
"0x006c55632dca03fe10c78f5e983cfd560ec55e587d930aa12ea50d75ea3262de0200000000000000008302a11ceb0b060000000701000602060a03101104210405252a074f42089101200000000100020103040100010004080001050304010002060607000107080501000002020202060c060c020b000108010b0001080101080102060c03010b000109000001060c010502050b000109000a6170746f735f636f696e04636f696e067369676e657204436f696e094170746f73436f696e0877697468647261770a616464726573735f6f66076465706f7369740000000000000000000000000000000000000000000000000000000000000001000001110a0006640000000000000038000c020a0106c80000000000000038000c030b0111010b0238010b0011010b033801020000400d0300000000006400000000000000b51f8c660000000002",
[{
"address": "0x7e3a6349ad8a43a6b7c3307b4b05d9008548a11673f440af5e516a9bc5114b3d",
"signature": "0x0020924795a3b1508fa51bed2b8539075eb410665114422aa80aac88732e3b92adbf4064a77a74aad50c1229dd65543d9d1cdd96542484328188ecaba585de6e22aff5de3b5bb65f76a630e5ab1ff2e32e62b59d31e65206b8e224f397db5bb36bc500"
}]
],
"id":1
}'
import { KeyClient, WalletClient } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
let sessionToken = await keyClient.createSession({{walletSecret}});
await walletClient.executeGaslessTransaction(
{{walletID}},
sessionToken,
{{transaction}},
[{{secondarySignatureOne}}, ...]
);
import { WalletClient, KeyClient, ShinamiWalletSigner } from "@shinami/clients/aptos";
const walletClient = new WalletClient({{walletServicesAccessKey}});
const keyClient = new KeyClient({{walletServicesAccessKey}});
const signer = new ShinamiWalletSigner(
{{walletId}},
walletClient,
{{walletSecret}},
keyClient
);
await signer.executeGaslessTransaction(
{{transaction}},
[{{secondarySignatureOne}}, ...]
);
# Here is an example of preparing a `RawTransaction` to be sent
# as the `rawTransaction` parameter
from aptos_sdk.bcs import Serializer
...
# Step 1:
# Build your RawTransaction with your Invisible Wallet address as the
# sender address. Below, we represent your RawTransaction
# with the variable `raw_transaction`
# Step 2:
# Prepare your RawTransaction to send to Shinami's API.
# Two options are shown below
# Option 1: send as an unsigned byte array
shinami_rawTransaction = list(raw_transaction.to_bytes())
# Option 2: send as a hex string
transaction_serializer = Serializer()
raw_transaction.serialize(transaction_serializer)
shinami_rawTransaction = transaction_serializer.output().hex()
Example Response
{
"id" : 1,
"jsonrpc" : "2.0",
"result" : {
"pendingTransaction" : {
"expiration_timestamp_secs" : "1720213435",
"gas_unit_price" : "150",
"hash" : "0xfee720e44614f8164da7d58333ef3947abbe997e3ac10451ee9a56f9788d8e34",
"max_gas_amount" : "200000",
"payload" : {
"arguments" : [
"hello"
],
"function" : "0xc13c3641ba3fc36e6a62f56e5a4b8a1f651dc5d9dc280bd349d5e4d0266d0817::message::set_message",
"type" : "entry_function_payload",
"type_arguments" : []
},
"sender" : "0x35d86428a7aee9863f9aa52d6aa4b583e2bcb7ee9d3e7d1cf1b6a7e13da503af",
"sequence_number" : "4",
"signature" : {
"fee_payer_address" : "0x2cdcec66a48b596c923024102feda5ee759197fe844c5ba56013d3b9a99287b6",
"fee_payer_signer" : {
"public_key" : "0x57b9d494d31ed56f902362eef6e9d4fa8d22e390ab921bcb1678c8ec915ecbcf",
"signature" : "0x1bb1186530bba89d8fa0d2706aba8d9908b11f7249f947e8833ecddd5dbb73f75fb8e325188631778d4ea4c8d10fafa03309f01b5373f1c5cac150b48bbddc09",
"type" : "ed25519_signature"
},
"secondary_signer_addresses" : [],
"secondary_signers" : [],
"sender" : {
"public_key" : "0x8880f82918ab4631f71a07e93f78b28254ab3abcb8cb8917d25c593eb60a3702",
"signature" : "0xb67b702ab701bf88800a764639a495b11baf3d1df3553030e33f4ef92342d2962d867be5be2731cf6d3bbfe3281f99a641c9f900185c90787448d1284b2e7e0e",
"type" : "ed25519_signature"
},
"type" : "fee_payer_signature"
}
}
}
}
{
"id" : 1,
"jsonrpc" : "2.0",
"result" : {
"pendingTransaction" : {
"expiration_timestamp_secs" : "1720459189",
"gas_unit_price" : "100",
"hash" : "0xd30736a7a854060ff449ea67451863e6134137303f7ac3439a16d46df1f9413e",
"max_gas_amount" : "200000",
"payload" : {
"arguments" : [],
"code" : {
"abi" : {
"generic_type_params" : [],
"is_entry" : true,
"is_view" : false,
"name" : "main",
"params" : [
"&signer",
"&signer"
],
"return" : [],
"visibility" : "public"
},
"bytecode" : "0xa11ceb0b060000000701000602060a03101104210405252a074f42089101200000000100020103040100010004080001050304010002060607000107080501000002020202060c060c020b000108010b0001080101080102060c03010b000109000001060c010502050b000109000a6170746f735f636f696e04636f696e067369676e657204436f696e094170746f73436f696e0877697468647261770a616464726573735f6f66076465706f7369740000000000000000000000000000000000000000000000000000000000000001000001110a0006640000000000000038000c020a0106c80000000000000038000c030b0111010b0238010b0011010b03380102"
},
"type" : "script_payload",
"type_arguments" : []
},
"sender" : "0x6c55632dca03fe10c78f5e983cfd560ec55e587d930aa12ea50d75ea3262de",
"sequence_number" : "2",
"signature" : {
"fee_payer_address" : "0x11045a6f53a6e9064fd92b45038649c334fd1afd60848a090facab14e07cf70a",
"fee_payer_signer" : {
"public_key" : "0x7dfd1009d1dff08cd60e900c1eccda628808016e5885bc82a66f4d97ba959594",
"signature" : "0x6ef8afa108df6ae0c50486dc0356e9e16abb9115d99ba6fac64a5fbcdd3e85c1775e3031511679458b4a574f55dd357919278acafc63dc124b9a70a663e8c706",
"type" : "ed25519_signature"
},
"secondary_signer_addresses" : [
"0x7e3a6349ad8a43a6b7c3307b4b05d9008548a11673f440af5e516a9bc5114b3d"
],
"secondary_signers" : [
{
"public_key" : "0x924795a3b1508fa51bed2b8539075eb410665114422aa80aac88732e3b92adbf",
"signature" : "0x64a77a74aad50c1229dd65543d9d1cdd96542484328188ecaba585de6e22aff5de3b5bb65f76a630e5ab1ff2e32e62b59d31e65206b8e224f397db5bb36bc500",
"type" : "ed25519_signature"
}
],
"sender" : {
"public_key" : "0xdc27624c0bf8ee11c8d6bf54e182b12a8f876eb56e66df740cb4de7adefbfa57",
"signature" : "0xf3bd6086a1381d36ce46dae5bf6aff2d9652a7d7ba846dacbb67b858ab20a6bf230c8f5b9c6b59d27b41d00ef0f8ec0b29e7e0335d4a4dbac4e2a6469375f50f",
"type" : "ed25519_signature"
},
"type" : "fee_payer_signature"
}
}
}
}
{
hash: '0x7a337a8952378b6a9174605b56c258f15b18f3a337ba766c02a624759f401c9f',
sender: '0x35d86428a7aee9863f9aa52d6aa4b583e2bcb7ee9d3e7d1cf1b6a7e13da503af',
sequence_number: '2',
max_gas_amount: '200000',
gas_unit_price: '150',
expiration_timestamp_secs: '1720131046',
payload: {
function: '0xc13c3641ba3fc36e6a62f56e5a4b8a1f651dc5d9dc280bd349d5e4d0266d0817::message::set_message',
type_arguments: [],
arguments: [ 'hello' ],
type: 'entry_function_payload'
},
signature: {
sender: {
public_key: '0x8880f82918ab4631f71a07e93f78b28254ab3abcb8cb8917d25c593eb60a3702',
signature: '0x3a446c1586ccec7bb98ad2010c7a13a238b163e096343ae7e9b858b2bd6de6cd5e7beaa6dccd67154bc5014aae4296ce13eda82668c643de99cfd547560f7801',
type: 'ed25519_signature'
},
secondary_signer_addresses: [],
secondary_signers: [],
fee_payer_address: '0x71d6c71f68f18ffab73b74b0680c790024324b882c3110d2ed81695e3102607e',
fee_payer_signer: {
public_key: '0x899562c7d7be4456219b6c08ebb4b0fbe5ad4525f3d74a514ff7390e9ddeb3a7',
signature: '0x8bb1f219fa65e036953c0ecf2d6aad017a4efd76c6ea493ac42c36ca93e8bbbe256d97ddd2cd2dc7f6e8b8bd5437041eec0cdfa18e52b0c6591d03f3c0061a02',
type: 'ed25519_signature'
},
type: 'fee_payer_signature'
}
}
{
hash: '0xd84a42c447049501d1ef334012c39b4602eb977df1c466652f59a1387c395b8f',
sender: '0x35d86428a7aee9863f9aa52d6aa4b583e2bcb7ee9d3e7d1cf1b6a7e13da503af',
sequence_number: '1',
max_gas_amount: '200000',
gas_unit_price: '150',
expiration_timestamp_secs: '1720130820',
payload: {
function: '0xc13c3641ba3fc36e6a62f56e5a4b8a1f651dc5d9dc280bd349d5e4d0266d0817::message::set_message',
type_arguments: [],
arguments: [ 'hello' ],
type: 'entry_function_payload'
},
signature: {
sender: {
public_key: '0x8880f82918ab4631f71a07e93f78b28254ab3abcb8cb8917d25c593eb60a3702',
signature: '0xccc9544d93c9563195d1596fbeeec33ae041439752114504d10592821cf3f24bd0bc006671c88e83e0449b42b41b5c06ab6f16ea5e70e8d945a0887584334207',
type: 'ed25519_signature'
},
secondary_signer_addresses: [],
secondary_signers: [],
fee_payer_address: '0x71d6c71f68f18ffab73b74b0680c790024324b882c3110d2ed81695e3102607e',
fee_payer_signer: {
public_key: '0x899562c7d7be4456219b6c08ebb4b0fbe5ad4525f3d74a514ff7390e9ddeb3a7',
signature: '0x607a3b86faf10153fd2afcb1ccec258f8e35dfb985fe2725efc77859a3f0b1e9c4e79de71c8357d8f9ee6f8508db7e0042dec270355a34c3d6d2964edd5bfb0e',
type: 'ed25519_signature'
},
type: 'fee_payer_signature'
}
}
Response Fields
Object with keys:
Name | Type | Description |
---|---|---|
pendingTransaction | cURL object (same shape as a PendingTransactionResponse )SDK PendingTransactionResponse | The submitted transaction waiting in mempool. |