cURL
curl --request POST \
--url https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-grid-environment: <x-grid-environment>' \
--data '
{
"kms_payloads": [
[
{
"kms_signed_payload": {
"public_key": "<string>",
"signature": "<string>",
"timestamp_ms": "<string>"
},
"signature": "<string>"
}
]
],
"transactions": [
"<string>"
]
}
'import requests
url = "https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit"
payload = {
"kms_payloads": [[
{
"kms_signed_payload": {
"public_key": "<string>",
"signature": "<string>",
"timestamp_ms": "<string>"
},
"signature": "<string>"
}
]],
"transactions": ["<string>"]
}
headers = {
"x-grid-environment": "<x-grid-environment>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-grid-environment': '<x-grid-environment>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
kms_payloads: [
[
{
kms_signed_payload: {public_key: '<string>', signature: '<string>', timestamp_ms: '<string>'},
signature: '<string>'
}
]
],
transactions: ['<string>']
})
};
fetch('https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'kms_payloads' => [
[
[
'kms_signed_payload' => [
'public_key' => '<string>',
'signature' => '<string>',
'timestamp_ms' => '<string>'
],
'signature' => '<string>'
]
]
],
'transactions' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"x-grid-environment: <x-grid-environment>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit"
payload := strings.NewReader("{\n \"kms_payloads\": [\n [\n {\n \"kms_signed_payload\": {\n \"public_key\": \"<string>\",\n \"signature\": \"<string>\",\n \"timestamp_ms\": \"<string>\"\n },\n \"signature\": \"<string>\"\n }\n ]\n ],\n \"transactions\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-grid-environment", "<x-grid-environment>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit")
.header("x-grid-environment", "<x-grid-environment>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"kms_payloads\": [\n [\n {\n \"kms_signed_payload\": {\n \"public_key\": \"<string>\",\n \"signature\": \"<string>\",\n \"timestamp_ms\": \"<string>\"\n },\n \"signature\": \"<string>\"\n }\n ]\n ],\n \"transactions\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-grid-environment"] = '<x-grid-environment>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"kms_payloads\": [\n [\n {\n \"kms_signed_payload\": {\n \"public_key\": \"<string>\",\n \"signature\": \"<string>\",\n \"timestamp_ms\": \"<string>\"\n },\n \"signature\": \"<string>\"\n }\n ]\n ],\n \"transactions\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"results": [
{
"confirmed_at": "2023-11-07T05:31:56Z",
"index": 1,
"transaction_signature": "<string>"
}
],
"partial_failure": {
"error_code": "<string>",
"error_message": "<string>",
"failed_at_index": 1
}
},
"metadata": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}Solana Support
Submit Transaction
Submit a previously prepared transaction with required signatures
POST
/
api
/
grid
/
v1
/
accounts
/
{address}
/
submit
cURL
curl --request POST \
--url https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-grid-environment: <x-grid-environment>' \
--data '
{
"kms_payloads": [
[
{
"kms_signed_payload": {
"public_key": "<string>",
"signature": "<string>",
"timestamp_ms": "<string>"
},
"signature": "<string>"
}
]
],
"transactions": [
"<string>"
]
}
'import requests
url = "https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit"
payload = {
"kms_payloads": [[
{
"kms_signed_payload": {
"public_key": "<string>",
"signature": "<string>",
"timestamp_ms": "<string>"
},
"signature": "<string>"
}
]],
"transactions": ["<string>"]
}
headers = {
"x-grid-environment": "<x-grid-environment>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-grid-environment': '<x-grid-environment>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
kms_payloads: [
[
{
kms_signed_payload: {public_key: '<string>', signature: '<string>', timestamp_ms: '<string>'},
signature: '<string>'
}
]
],
transactions: ['<string>']
})
};
fetch('https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'kms_payloads' => [
[
[
'kms_signed_payload' => [
'public_key' => '<string>',
'signature' => '<string>',
'timestamp_ms' => '<string>'
],
'signature' => '<string>'
]
]
],
'transactions' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"x-grid-environment: <x-grid-environment>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit"
payload := strings.NewReader("{\n \"kms_payloads\": [\n [\n {\n \"kms_signed_payload\": {\n \"public_key\": \"<string>\",\n \"signature\": \"<string>\",\n \"timestamp_ms\": \"<string>\"\n },\n \"signature\": \"<string>\"\n }\n ]\n ],\n \"transactions\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-grid-environment", "<x-grid-environment>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit")
.header("x-grid-environment", "<x-grid-environment>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"kms_payloads\": [\n [\n {\n \"kms_signed_payload\": {\n \"public_key\": \"<string>\",\n \"signature\": \"<string>\",\n \"timestamp_ms\": \"<string>\"\n },\n \"signature\": \"<string>\"\n }\n ]\n ],\n \"transactions\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://grid.squads.xyz/api/grid/v1/accounts/{address}/submit")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-grid-environment"] = '<x-grid-environment>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"kms_payloads\": [\n [\n {\n \"kms_signed_payload\": {\n \"public_key\": \"<string>\",\n \"signature\": \"<string>\",\n \"timestamp_ms\": \"<string>\"\n },\n \"signature\": \"<string>\"\n }\n ]\n ],\n \"transactions\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"results": [
{
"confirmed_at": "2023-11-07T05:31:56Z",
"index": 1,
"transaction_signature": "<string>"
}
],
"partial_failure": {
"error_code": "<string>",
"error_message": "<string>",
"failed_at_index": 1
}
},
"metadata": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}This endpoint submits a previously prepared transaction to the blockchain after verifying the required signatures from Grid Account authorization keys.
Using the Grid API directly requires advanced configurations. Grid SDK is the recommended
way to submit transactions. It handles transaction preparation, signing, automatic failover, and
submission. Learn more about the Grid SDK in the Grid SDK guide.
This endpoint requires a prepared transaction and valid signatures. Use transaction
preparation endpoints first, then sign the KMS payload with your decrypted authorization key
before calling this endpoint.
Account Type Signing Flows
Grid supports two types of accounts with different signing requirements. Choose the appropriate flow based on how your account was created:Email-based Account Signing Flow
Email-based Account Signing Flow
For accounts created with email authentication (using Privy):
High-Level Process
- Prepare Transaction: Call transaction preparation endpoints (payments, transfers, etc.)
- Receive KMS Payload: Extract the
kms_payloadfrom the preparation response - Sign Payload: Use your decrypted Privy authorization key to sign the canonical JSON
- Submit Transaction: Call this endpoint with the signature and transaction data
Key Requirements
- Authorization keys from email account creation/authentication
- JSON canonicalization of the KMS payload (recursive key sorting)
- ECDSA P-256 SHA-256 signature algorithm
Complete Implementation Guide
For detailed implementation including HPKE keypair generation, authorization key decryption, JSON canonicalization, payload signing, and language-agnostic examples, see the Primary Provider Integration guide.Signer-based Account Signing Flow
Signer-based Account Signing Flow
For accounts created with Ed25519 public keys:The signed transaction proves you have access to the required number of Grid Account signing keys and authorizes the transaction execution.
Signing Process
- Prepare Transaction: Call transaction preparation endpoints (payments, transfers, etc.)
- Receive Transaction: Extract the prepared Solana transaction from the response
- Sign Transaction: Use your Ed25519 private keys with standard Solana transaction signing (e.g., web3.js)
- Submit Transaction: Call this endpoint with the signed transaction
Signature Requirements
- Ed25519 private keys corresponding to the public keys specified during account creation
- Threshold signatures meeting the account’s signing threshold
- Standard Solana transaction signing (no KMS payload or JSON canonicalization required)
Signer-based accounts use regular Solana transaction signing with libraries like
web3.js. No KMS payload processing or JSON canonicalization is required.
Implementation with web3.js
import { Transaction } from '@solana/web3.js';
import { Keypair } from '@solana/web3.js';
// Extract prepared transaction from API response
const preparedTransaction = Transaction.from(
Buffer.from(response.transaction, 'base64')
);
// Sign with your Ed25519 keypairs (threshold signatures required)
const signers = [keypair1, keypair2]; // Your Ed25519 keypairs
preparedTransaction.sign(...signers);
// Submit the signed transaction
const signedTransaction = preparedTransaction.serialize();
KMS Payload Schema
Thekms_payloads field contains the signed KMS payloads from your key management provider. Each payload has a provider and a kms_signed_payload whose shape depends on the provider. See the auto-generated request body schema below for full field details.
Turnkey accounts must use
kms_signed_payload. The top-level signature field is only
supported for Privy as a legacy fallback.Request Examples
Single Transaction (Privy)
Single Transaction (Privy)
{
"transaction": "<base64_encoded_transaction>",
"kms_payloads": [
{
"provider": "privy",
"kms_signed_payload": {
"signature": "<base64_der_ecdsa_signature>"
}
}
]
}
Single Transaction (Turnkey)
Single Transaction (Turnkey)
{
"transaction": "<base64_encoded_transaction>",
"kms_payloads": [
{
"provider": "turnkey",
"kms_signed_payload": {
"public_key": "<hex_p256_public_key>",
"signature": "<hex_signature>",
"timestamp_ms": "<unix_timestamp_ms>"
}
}
]
}
Multiple Transactions
Multiple Transactions
When submitting multiple transactions, use
transactions (plural) and nest kms_payloads as an array of arrays — one inner array per transaction:{
"transactions": ["<base64_tx_1>", "<base64_tx_2>"],
"kms_payloads": [
[
{
"provider": "privy",
"kms_signed_payload": {
"signature": "<signature_for_tx_1>"
}
}
],
[
{
"provider": "privy",
"kms_signed_payload": {
"signature": "<signature_for_tx_2>"
}
}
]
]
}
Legacy Format (Privy only, backward-compatible)
Legacy Format (Privy only, backward-compatible)
This format places the signature at the top level instead of inside
kms_signed_payload. It is supported for backward compatibility with Privy accounts only.{
"transaction": "<base64_encoded_transaction>",
"kms_payloads": [
{
"provider": "privy",
"signature": "<base64_der_ecdsa_signature>"
}
]
}
Authorizations
Your Grid API key from the Grid Dashboard
Headers
Solana network environment (sandbox, devnet, mainnet)
Path Parameters
Smart account address (Solana public key)
Body
application/json
Was this page helpful?