Create smart account with passkey
curl --request POST \
--url https://grid.squads.xyz/api/grid/v1/passkeys/account \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-grid-environment: <x-grid-environment>' \
--data '
{
"authenticatorResponse": {},
"sessionKey": {
"expiration": 1,
"key": "11111111111111111111111111111111"
},
"slotNumber": 1,
"adminAddress": "<string>",
"memo": "<string>"
}
'import requests
url = "https://grid.squads.xyz/api/grid/v1/passkeys/account"
payload = {
"authenticatorResponse": {},
"sessionKey": {
"expiration": 1,
"key": "11111111111111111111111111111111"
},
"slotNumber": 1,
"adminAddress": "<string>",
"memo": "<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({
authenticatorResponse: {},
sessionKey: {expiration: 1, key: '11111111111111111111111111111111'},
slotNumber: 1,
adminAddress: '<string>',
memo: '<string>'
})
};
fetch('https://grid.squads.xyz/api/grid/v1/passkeys/account', 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/passkeys/account",
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([
'authenticatorResponse' => [
],
'sessionKey' => [
'expiration' => 1,
'key' => '11111111111111111111111111111111'
],
'slotNumber' => 1,
'adminAddress' => '<string>',
'memo' => '<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/passkeys/account"
payload := strings.NewReader("{\n \"authenticatorResponse\": {},\n \"sessionKey\": {\n \"expiration\": 1,\n \"key\": \"11111111111111111111111111111111\"\n },\n \"slotNumber\": 1,\n \"adminAddress\": \"<string>\",\n \"memo\": \"<string>\"\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/passkeys/account")
.header("x-grid-environment", "<x-grid-environment>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"authenticatorResponse\": {},\n \"sessionKey\": {\n \"expiration\": 1,\n \"key\": \"11111111111111111111111111111111\"\n },\n \"slotNumber\": 1,\n \"adminAddress\": \"<string>\",\n \"memo\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://grid.squads.xyz/api/grid/v1/passkeys/account")
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 \"authenticatorResponse\": {},\n \"sessionKey\": {\n \"expiration\": 1,\n \"key\": \"11111111111111111111111111111111\"\n },\n \"slotNumber\": 1,\n \"adminAddress\": \"<string>\",\n \"memo\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"address": "5nPmK...smartAccountAddress",
"type": "passkey",
"status": "active",
"policies": {
"threshold": 1,
"admin_address": null
},
"authentication": [
{
"provider": "passkey",
"session": {
"Passkey": {
"passkey_account": "7xK2...passkeyAddress",
"pubkey": "base58EncodedPublicKey",
"relying_party_id": "grid.squads.xyz",
"session_key": {
"key": "sessionPublicKey",
"expiration": 1706832000
}
}
}
}
],
"created_at": "2025-02-01T12:00:00Z",
"updated_at": "2025-02-01T12:00:00Z"
}
Passkeys
Create Smart Account
Create a passkey and Grid smart account in one atomic operation.
Create smart account with passkey
curl --request POST \
--url https://grid.squads.xyz/api/grid/v1/passkeys/account \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-grid-environment: <x-grid-environment>' \
--data '
{
"authenticatorResponse": {},
"sessionKey": {
"expiration": 1,
"key": "11111111111111111111111111111111"
},
"slotNumber": 1,
"adminAddress": "<string>",
"memo": "<string>"
}
'import requests
url = "https://grid.squads.xyz/api/grid/v1/passkeys/account"
payload = {
"authenticatorResponse": {},
"sessionKey": {
"expiration": 1,
"key": "11111111111111111111111111111111"
},
"slotNumber": 1,
"adminAddress": "<string>",
"memo": "<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({
authenticatorResponse: {},
sessionKey: {expiration: 1, key: '11111111111111111111111111111111'},
slotNumber: 1,
adminAddress: '<string>',
memo: '<string>'
})
};
fetch('https://grid.squads.xyz/api/grid/v1/passkeys/account', 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/passkeys/account",
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([
'authenticatorResponse' => [
],
'sessionKey' => [
'expiration' => 1,
'key' => '11111111111111111111111111111111'
],
'slotNumber' => 1,
'adminAddress' => '<string>',
'memo' => '<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/passkeys/account"
payload := strings.NewReader("{\n \"authenticatorResponse\": {},\n \"sessionKey\": {\n \"expiration\": 1,\n \"key\": \"11111111111111111111111111111111\"\n },\n \"slotNumber\": 1,\n \"adminAddress\": \"<string>\",\n \"memo\": \"<string>\"\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/passkeys/account")
.header("x-grid-environment", "<x-grid-environment>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"authenticatorResponse\": {},\n \"sessionKey\": {\n \"expiration\": 1,\n \"key\": \"11111111111111111111111111111111\"\n },\n \"slotNumber\": 1,\n \"adminAddress\": \"<string>\",\n \"memo\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://grid.squads.xyz/api/grid/v1/passkeys/account")
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 \"authenticatorResponse\": {},\n \"sessionKey\": {\n \"expiration\": 1,\n \"key\": \"11111111111111111111111111111111\"\n },\n \"slotNumber\": 1,\n \"adminAddress\": \"<string>\",\n \"memo\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"address": "5nPmK...smartAccountAddress",
"type": "passkey",
"status": "active",
"policies": {
"threshold": 1,
"admin_address": null
},
"authentication": [
{
"provider": "passkey",
"session": {
"Passkey": {
"passkey_account": "7xK2...passkeyAddress",
"pubkey": "base58EncodedPublicKey",
"relying_party_id": "grid.squads.xyz",
"session_key": {
"key": "sessionPublicKey",
"expiration": 1706832000
}
}
}
}
],
"created_at": "2025-02-01T12:00:00Z",
"updated_at": "2025-02-01T12:00:00Z"
}
The “Try It” feature is disabled because this endpoint requires a WebAuthn authenticator response. Use the Integration Guide for implementation examples.
authenticatorResponse directly—the passkey does not need to exist beforehand.
This endpoint creates the passkey from your WebAuthn response. You do not need to call
/passkeys/submit first.What Gets Created
In one transaction:- Passkey account — derived from your WebAuthn public key
- 1/1 smart account — with the passkey as sole signer (mask=7: full permissions)
- Database records — GridUser, GridSmartAccount, and audit trail
- 1 USDC funding — sandbox only
Implementation Flow (Direct API)
1
Generate Session Key
Create a Solana keypair for the session.
2
Get Current Slot
Fetch the current Solana slot number for replay protection.
3
Trigger WebAuthn
Call
navigator.credentials.create() to create the passkey on the user’s device.4
Call This Endpoint
Pass the raw
authenticatorResponse to create both accounts atomically.// After WebAuthn ceremony completes
const response = await fetch("/passkeys/account", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY",
"x-grid-environment": "sandbox"
},
body: JSON.stringify({
sessionKey: { key: sessionPublicKey, expiration: 900 },
slotNumber: currentSlot,
authenticatorResponse: credential.response // raw WebAuthn response
})
});
Timing Constraints
TheslotNumber must be within Solana’s SlotHashes window (~3 minutes / 512 slots). If you encounter slot-related errors, fetch a fresh slot and retry.
Environment Isolation: Smart accounts have different addresses in sandbox vs production. Never send funds to the wrong environment.
Related Endpoints
- Create Passkey Session — Hosted UI flow (alternative)
- Integration Guide — Complete implementation examples
{
"address": "5nPmK...smartAccountAddress",
"type": "passkey",
"status": "active",
"policies": {
"threshold": 1,
"admin_address": null
},
"authentication": [
{
"provider": "passkey",
"session": {
"Passkey": {
"passkey_account": "7xK2...passkeyAddress",
"pubkey": "base58EncodedPublicKey",
"relying_party_id": "grid.squads.xyz",
"session_key": {
"key": "sessionPublicKey",
"expiration": 1706832000
}
}
}
}
],
"created_at": "2025-02-01T12:00:00Z",
"updated_at": "2025-02-01T12:00:00Z"
}
Authorizations
Your Grid API key from the Grid Dashboard
Headers
Solana network environment (sandbox, devnet, mainnet)
Body
application/json
Grid v1 API SessionKey type that supports backward-compatible deserialization from both raw bytes array (old format) and base58 string (new format). Always serializes to base58 string format.
Show child attributes
Show child attributes
Required range:
x >= 0Was this page helpful?