```json
[
{
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"metadata": {
"version": 1,
"name": "Example account",
"logo": { "type": "emoji", "value": "π" },
"description": "SDK test account"
},
"status": "active",
"namespace": "eip155",
"address": "0x1111111111111111111111111111111111111111",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000005",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "7702",
"delegationVersion": "v1.1.0"
},
"createdAt": "2026-10-11T09:00:00.000Z",
"updatedAt": "2026-10-11T09:00:00.000Z"
}
]
```
## List Session Keys [#list-session-keys]
```ts title="index.ts"
const sessions = await namera.sessionKeys.list();
if (!sessions.success) throw new Error(sessions.error.message);
console.log(sessions.data);
const session = sessions.data[0];
if (!session) throw new Error("Grant this API key access to your session key.");
```
This uses the first key returned. For this walkthrough, your API key should only
have access to the session key you just configured.
```json
[
{
"id": "0199dfe1-0000-7000-8000-000000000002",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"signingKeyId": "0199dfe1-0000-7000-8000-000000000006",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Example session",
"logo": { "type": "emoji", "value": "π" },
"description": "Send 0.001 test ETH on Base Sepolia"
},
"policies": [],
"policyHash": "1111111111111111111111111111111111111111111111111111111111111111",
"status": "active",
"revokedAt": null,
"createdAt": "2026-10-11T09:05:00.000Z",
"signer": {
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1",
"publicKey": "0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"metadata": {
"version": 1,
"name": "Example account",
"logo": { "type": "emoji", "value": "π" },
"description": "SDK test account"
},
"status": "active",
"namespace": "eip155",
"address": "0x1111111111111111111111111111111111111111",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000005",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "7702",
"delegationVersion": "v1.1.0"
},
"createdAt": "2026-10-11T09:00:00.000Z",
"updatedAt": "2026-10-11T09:00:00.000Z"
},
"creator": {
"organizationMember": {
"id": "0199dfe1-0000-7000-8000-000000000007",
"userId": "0199dfe1-0000-7000-8000-000000000008",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"organizationRoleId": "0199dfe1-0000-7000-8000-000000000009",
"joinedAt": "2026-10-11T08:00:00.000Z"
},
"user": {
"id": "0199dfe1-0000-7000-8000-000000000008",
"email": "developer@example.com",
"emailVerified": true,
"metadata": {
"version": 1,
"name": "Example developer",
"image": { "type": "emoji", "value": "π€" }
},
"lastLoginAt": "2026-10-11T08:55:00.000Z"
},
"organizationRole": {
"id": "0199dfe1-0000-7000-8000-000000000009",
"key": "developer",
"metadata": {
"version": 1,
"name": "Developer",
"logo": { "type": "emoji", "value": "π»" },
"description": "Manage test accounts and session keys"
},
"type": "custom",
"permissions": [
"wallet:read",
"wallet:create",
"session-key:read",
"session-key:create",
"api-key:create"
],
"systemRoleId": null
}
},
"installations": [
{
"id": "0199dfe1-0000-7000-8000-000000000010",
"chainId": "eip155:84532",
"status": "installed",
"authorization": {
"version": 1,
"entityId": 1,
"signerAddress": "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf",
"permissions": [
{ "type": "contract-access", "address": "0x2222222222222222222222222222222222222222" },
{ "type": "native-token-transfer", "allowance": "1000000000000000" }
],
"allowSignatures": false,
"validAfter": 1791709200,
"validUntil": 1794387600
},
"installTransactionHash": "0x2222222222222222222222222222222222222222222222222222222222222222",
"uninstallTransactionHash": null
}
]
}
]
```
## Execute a Transaction [#execute-a-transaction]
This sends **0.001 test ETH** on Base Sepolia. Replace the example address below
with the separate recipient wallet allowed by your session key.
```ts title="index.ts"
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: session.walletId,
sessionKeyId: session.id,
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "prepared",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
## Get Submission Status [#get-submission-status]
Use the submission ID from the execution result:
```ts title="index.ts"
const status = await namera.executions.getStatus(execution.data.submissionId);
if (!status.success) throw new Error(status.error.message);
console.log(status.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "submitted",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
Check the same submission again after a short delay while its status is
`reserved`, `prepared`, or `submitted`. Stop on `confirmed` or `failed`.
- **Confirmed:** `status.data.execution` contains the execution record.
- **Failed:** the submission did not complete successfully.
```json
{
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000006",
"metadata": {
"version": 1,
"name": "Provisioned account"
},
"status": "active",
"namespace": "eip155",
"address": "0x3333333333333333333333333333333333333333",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000008",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"createdAt": "2026-10-15T02:39:05.250Z",
"updatedAt": "2026-10-15T02:39:05.250Z",
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "factory",
"factoryVersion": "2.0.0",
"implementationVersion": "v1.0.0",
"ownerAddress": "0x52e7f17258368d7f9Ebd7bDf8d6869Bc4759aBA1",
"salt": "0"
}
}
```
The account is derived and persisted without deploying it. The SDK manages managed-provisioning retry keys internally. Keep the returned ID; use it as `walletId` when creating sessions.
## Create a passkey-owned account [#create-a-passkey-owned-account]
At API-key issuance, allowlist your applicationβs exact origin, such as `https://app.example.com`. Each passkey belongs to that RP and origin. Your backend must authenticate its application user and bind the pending verification ID to that user.
### Start on your backend [#start-on-your-backend]
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const result = await namera.wallets.createPasskeyRegistrationOptions({
origin: "https://app.example.com",
user: { name: "Customer", displayName: "Customer" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```json
{
"verificationId": "0199dfe1-0000-7000-8000-000000000022",
"options": {
"challenge": "OuAZdeWe1cPGP8if-E91tdEwtCgFVy68KEuEyXdtaIY",
"rp": {
"id": "app.example.com",
"name": "Namera"
},
"user": {
"id": "MDFhMTNkNmQtNzZkYi03NTUzLWE4M2QtMTFhMzRkNWJhNjFm",
"name": "Customer",
"displayName": "Customer"
},
"pubKeyCredParams": [
{
"alg": -7,
"type": "public-key"
}
],
"timeout": 300000,
"excludeCredentials": [],
"authenticatorSelection": {
"residentKey": "required",
"requireResidentKey": true,
"userVerification": "required"
},
"hints": [],
"attestation": "none",
"extensions": {
"credProps": true
}
},
"expiresAt": "2026-10-15T02:44:06.347Z"
}
```
Persist `verificationId` in your userβs pending account creation and return `options` to their browser. Do not expose the API key. Your application owns the start/finish HTTP routes; these are not additional Namera endpoints.
### Register in the browser [#register-in-the-browser]
Install `@simplewebauthn/browser` in your frontend. In a user-initiated event, call `startRegistration({ optionsJSON: options })` with the options your backend returned. Send the complete result to your backend. Browser cancellation should leave the account uncreated.
### Finish on your backend [#finish-on-your-backend]
Load `verificationId` from that authenticated userβs pending creation and submit:
```ts title="index.ts"
import { NameraClient, type CreateWalletRequest } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
export async function finishPasskeyAccount(
verificationId: string,
response: Extract["response"],
) {
const result = await namera.wallets.create({
namespace: "eip155",
metadata: { version: 1, name: "Customer account" },
owner: { type: "passkey", verificationId, response },
});
if (!result.success) throw new Error(result.error.message);
return result.data;
}
```
```json
{
"id": "0199dfe1-0000-7000-8000-000000000004",
"organizationId": "0199dfe1-0000-7000-8000-000000000015",
"metadata": {
"version": 1,
"name": "Customer account"
},
"status": "active",
"namespace": "eip155",
"address": "0x3333333333333333333333333333333333333333",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000016",
"custody": "local",
"algorithm": "p256"
},
"createdAt": "2026-10-15T02:39:06.474Z",
"updatedAt": "2026-10-15T02:39:06.474Z",
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "webauthn_p256",
"entryPointVersion": "0.7",
"salt": "0",
"entityId": 0
}
}
```
The exported function is called by your authenticated finish route after it loads the pending verification. It is not an unauthenticated route accepting arbitrary verification IDs. Registration is single-use and actor-bound. Passkey creation is not automatically retried after a lost response; inspect the workspace account list before attempting a new ceremony.
Next, [create a session key](https://namera.ai/docs/sdk/guides/accounts/create-session-keys).
# Create Session Keys
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/accounts/create-session-keys
Register a managed or caller-held session signer.
Issue an API key with `session-key:create`, `session-key:read`, and `wallet:read`. You need an account ID in that workspace. Session custody is independent of account ownership: both signer types work with either account owner.
## Create a managed session [#create-a-managed-session]
The following example deliberately requests root authority for one hour on Sepolia, with message signatures disabled. Root sessions can control the account; select narrower onchain permissions for restricted agents.
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const result = await namera.sessionKeys.create({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
metadata: { version: 1, name: "Local agent" },
signer: { custody: "namera-managed", provider: "1claw", algorithm: "secp256k1" },
onchain: {
installations: [
{
chainId: "eip155:11155111",
validAfter: Math.floor(Date.now() / 1000),
validUntil: Math.floor(Date.now() / 1000) + 3600,
permissions: [{ type: "root" }],
allowSignatures: false,
},
],
},
policies: [],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```json
{
"id": "0199dfe1-0000-7000-8000-000000000003",
"organizationId": "0199dfe1-0000-7000-8000-000000000006",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"signingKeyId": "0199dfe1-0000-7000-8000-000000000012",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Local agent"
},
"policies": [],
"policyHash": "9Z4ZzPfiQ4hIUpSXTY_nQ2E9-kjd2w_5wbLwIj7visI",
"status": "pending",
"revokedAt": null,
"createdAt": "2026-10-15T02:39:05.307Z",
"signer": {
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1",
"publicKey": "0x04e37a5065266fa599595e06a6968cdfe2d588cfbbbbb48f0d4c504048c53786a87ff061f472d579833ea98e99f425febabd2445a8760e225cb1e5b4a029cd18b8"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000006",
"metadata": {
"version": 1,
"name": "Provisioned account"
},
"status": "active",
"namespace": "eip155",
"address": "0x3333333333333333333333333333333333333333",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000008",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"createdAt": "2026-10-15T02:39:05.250Z",
"updatedAt": "2026-10-15T02:39:05.250Z",
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "factory",
"factoryVersion": "2.0.0",
"implementationVersion": "v1.0.0",
"ownerAddress": "0x52e7f17258368d7f9Ebd7bDf8d6869Bc4759aBA1",
"salt": "0"
}
},
"creator": {
"type": "api-key",
"actorId": "0199dfe1-0000-7000-8000-000000000009",
"id": "0199dfe1-0000-7000-8000-000000000010",
"metadata": {
"version": 1,
"name": "Workspace backend"
}
},
"installations": [
{
"id": "0199dfe1-0000-7000-8000-000000000013",
"chainId": "eip155:11155111",
"status": "pending",
"authorization": {
"version": 1,
"entityId": 142534698,
"signerAddress": "0x7838CE7D0AC8943A2fAA4e8ab8ae901b05eA7A03",
"permissions": [
{
"type": "root"
}
],
"allowSignatures": false,
"validAfter": 1792031945,
"validUntil": 1792035545
},
"installTransactionHash": null,
"uninstallTransactionHash": null
}
]
}
```
The SDK manages managed-provisioning idempotency internally. Namera returns public signer information only.
## Create a local session [#create-a-local-session]
Install `viem` alongside `@namera-ai/sdk`. Generate and securely persist your private key locally before registering its public key:
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const privateKey = generatePrivateKey();
const signer = privateKeyToAccount(privateKey);
// Persist the private key in your secure signer store before registration.
const now = Math.floor(Date.now() / 1000);
const result = await namera.sessionKeys.create({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
metadata: { version: 1, name: "Local agent" },
signer: { custody: "local", algorithm: "secp256k1", publicKey: signer.publicKey },
onchain: {
installations: [
{
chainId: "eip155:11155111",
validAfter: now,
validUntil: now + 3600,
permissions: [{ type: "root" }],
allowSignatures: false,
},
],
},
policies: [],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```json
{
"id": "0199dfe1-0000-7000-8000-000000000002",
"organizationId": "0199dfe1-0000-7000-8000-000000000006",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"signingKeyId": "0199dfe1-0000-7000-8000-000000000007",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Local agent"
},
"policies": [],
"policyHash": "9Z4ZzPfiQ4hIUpSXTY_nQ2E9-kjd2w_5wbLwIj7visI",
"status": "pending",
"revokedAt": null,
"createdAt": "2026-10-15T02:39:05.274Z",
"signer": {
"custody": "local",
"algorithm": "secp256k1",
"publicKey": "0x04118cf91563c3c7b00440980e879331bdac649585ea668f5dfdb0d925ae6bc4bc2ce5449ea5eabee69642fa1b6df0dce03b2dc3e7ae4498878013772fdd155cb6"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000006",
"metadata": {
"version": 1,
"name": "Provisioned account"
},
"status": "active",
"namespace": "eip155",
"address": "0x3333333333333333333333333333333333333333",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000008",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"createdAt": "2026-10-15T02:39:05.250Z",
"updatedAt": "2026-10-15T02:39:05.250Z",
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "factory",
"factoryVersion": "2.0.0",
"implementationVersion": "v1.0.0",
"ownerAddress": "0x52e7f17258368d7f9Ebd7bDf8d6869Bc4759aBA1",
"salt": "0"
}
},
"creator": {
"type": "api-key",
"actorId": "0199dfe1-0000-7000-8000-000000000009",
"id": "0199dfe1-0000-7000-8000-000000000010",
"metadata": {
"version": 1,
"name": "Workspace backend"
}
},
"installations": [
{
"id": "0199dfe1-0000-7000-8000-000000000011",
"chainId": "eip155:11155111",
"status": "pending",
"authorization": {
"version": 1,
"entityId": 145278918,
"signerAddress": "0xdA46572b24FF407Cb8979412281cEA774087E5d7",
"permissions": [
{
"type": "root"
}
],
"allowSignatures": false,
"validAfter": 1792031945,
"validUntil": 1792035545
},
"installTransactionHash": null,
"uninstallTransactionHash": null
}
]
}
```
The private key never enters a Namera request. Public-key registration does not populate the SDKβs Node signer store. For execution, configure your trusted local signer binding or use the existing encrypted local-key import flow. Retain the signer after a lost registration response; do not generate a replacement key as a retry.
## Approve installation separately [#approve-installation-separately]
Creation grants the calling API-key actor access to the new session, but does not install it. Each installation starts pending. [Install the session](https://namera.ai/docs/sdk/guides/accounts/install-session-keys) before executing or signing.
# Install Session Keys
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/accounts/install-session-keys
Explicitly approve and track session installation from the SDK.
Use an API key with `session-key:read` and `session-key:install`. You need a registered session with an unexpired pending installation on the chosen network. The accountβs owner determines approval; the session signerβs custody does not.
These are low-level owner-operation methods. Review the selected account, signer, permissions, network, validity, and fees before approving. Use the SDKβs `validateManagedOwnerApproval` or `validateOwnerApproval` helpers with independently reconstructed expectations when validating prepared calldata. Do not populate those expectations from the preparation you are validating.
## Prepare installation [#prepare-installation]
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const result = await namera.sessionKeys.prepareOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003",
chainId: "eip155:11155111",
kind: "install",
sponsor: true,
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000000014",
"namespace": "eip155",
"approval": "1claw",
"prepared": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"entryPointVersion": "0.7",
"entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"sponsorship": "alchemy-bso",
"context": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"account": "0x3333333333333333333333333333333333333333",
"block": {
"number": "0",
"hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "1970-01-01T00:00:00.000Z"
},
"calls": [
{
"to": "0x3333333333333333333333333333333333333333",
"value": "0",
"data": "0x1234"
}
],
"userOperation": {
"nonce": "0",
"gas": {
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"paymasterVerificationGasLimit": "0",
"paymasterPostOpGasLimit": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0"
},
"paymaster": null
},
"simulation": {
"userOperation": {
"source": "eth_estimateUserOperationGas",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "1000000000",
"maxPriorityFeePerGas": "1"
},
"calls": {
"source": "viem.simulateCalls",
"results": [
{
"status": "success",
"returnData": "0x",
"gasUsed": "0"
}
],
"assetChanges": [],
"transfers": []
}
}
},
"userOperation": {
"sender": "0x3333333333333333333333333333333333333333",
"nonce": "0",
"callData": "0x",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0",
"signature": "0x"
},
"billing": {
"executionMeter": "execution.testnet",
"sponsorship": null
}
},
"expiresAt": "2026-10-15T02:44:05.075Z"
}
```
The SDK resolves the sessionβs network installation and account owner, then chooses the existing managed or passkey preparation endpoint. Retry keys stay internal. Preparation does not sign or submit.
## Approve a managed account operation [#approve-a-managed-account-operation]
After reviewing and validating the preparation, explicitly approve its operation ID:
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const result = await namera.sessionKeys.approveOperation({
operationId: "0199dfe1-0000-7000-8000-000000000014",
approval: { type: "1claw" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000000014",
"status": "signed"
}
```
This call authorizes the managed account owner to sign only the stored installation. Creating the session did not grant this approval.
## Approve a passkey account operation [#approve-a-passkey-account-operation]
Passkey preparation returns `approval: "passkey"` and `options`:
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000000021",
"namespace": "eip155",
"options": {
"challenge": "ERERERERERERERERERERERERERERERERERERERERERE",
"rpId": "app.example.com",
"timeout": 300000,
"allowCredentials": [
{
"id": "fH9q_W4I4NAClGWOrbumZv4mrefSBfKPdY2UFfTKvcI",
"type": "public-key"
}
],
"userVerification": "required"
},
"prepared": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"entryPointVersion": "0.7",
"entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"sponsorship": "alchemy-bso",
"context": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"account": "0x3333333333333333333333333333333333333333",
"block": {
"number": "0",
"hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "1970-01-01T00:00:00.000Z"
},
"calls": [
{
"to": "0x3333333333333333333333333333333333333333",
"value": "0",
"data": "0x1234"
}
],
"userOperation": {
"nonce": "0",
"gas": {
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"paymasterVerificationGasLimit": "0",
"paymasterPostOpGasLimit": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0"
},
"paymaster": null
},
"simulation": {
"userOperation": {
"source": "eth_estimateUserOperationGas",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "1000000000",
"maxPriorityFeePerGas": "1"
},
"calls": {
"source": "viem.simulateCalls",
"results": [
{
"status": "success",
"returnData": "0x",
"gasUsed": "0"
}
],
"assetChanges": [],
"transfers": []
}
}
},
"userOperation": {
"sender": "0x3333333333333333333333333333333333333333",
"nonce": "0",
"callData": "0x",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0",
"signature": "0x"
},
"billing": {
"executionMeter": "execution.testnet",
"sponsorship": null
}
},
"expiresAt": "2026-10-15T02:44:06.347Z"
}
```
Return the preparation to your applicationβs browser for review and validation. Install `@simplewebauthn/browser` in your frontend and call `startAuthentication({ optionsJSON: preparation.options })` from a user action. The prompt must run on the accountβs stored origin. Keep the API key on your backend.
Send the assertion to your authenticated backend, which loads the pending operation ID belonging to that user and calls:
```ts title="index.ts"
import { NameraClient, type ApproveSessionKeyOperationRequest } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
export async function finishPasskeyInstallation(
operationId: string,
response: Extract["response"],
) {
const result = await namera.sessionKeys.approveOperation({
operationId,
approval: { type: "passkey", response },
});
if (!result.success) throw new Error(result.error.message);
return result.data;
}
```
The success shape is the same operation status shown above. Namera verifies the actual assertion; an API-key permission does not replace the passkey signature.
## Track confirmation and recover interruptions [#track-confirmation-and-recover-interruptions]
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const result = await namera.sessionKeys.getOperation("0199dfe1-0000-7000-8000-000000000014");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000000014",
"status": "confirmed"
}
```
Workers submit signed requests and reconcile receipts. `signed` and `submitted` are not confirmation. Check the session installation for `installed` before using it.
After a restart, call `sessionKeys.getActiveOperation({ sessionKeyId, chainId, kind: "install" })`. An unsigned operation includes a recovered `preparation`; review it before explicit approval. Signed/submitted operations include no preparation and should be polled. No caller-managed idempotency key is needed. `cancelOperation(operationId)` cancels an unsigned preparation; it cannot cancel signed work.
# Revoke and Remove Session Keys
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/accounts/revoke-session-keys
Stop Namera access and remove remaining onchain authority.
Use `session-key:revoke`, `session-key:uninstall`, and `session-key:read` on a workspace management key. These are separate permissions and actions.
## Revoke Namera access [#revoke-namera-access]
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const result = await namera.sessionKeys.revoke("0199dfe1-0000-7000-8000-000000001000");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```json
{
"id": "0199dfe1-0000-7000-8000-000000001000",
"organizationId": "0199dfe1-0000-7000-8000-000000001001",
"walletId": "0199dfe1-0000-7000-8000-000000001002",
"signingKeyId": "0199dfe1-0000-7000-8000-000000001003",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Local agent"
},
"policies": [],
"policyHash": "9Z4ZzPfiQ4hIUpSXTY_nQ2E9-kjd2w_5wbLwIj7visI",
"status": "revoking",
"revokedAt": "2026-10-15T02:57:34.211Z",
"createdAt": "2026-10-15T02:57:32.375Z",
"signer": {
"custody": "local",
"algorithm": "secp256k1",
"publicKey": "0x04c70cd5e6b1350f36bb3f47e4c50f276178a843ddc457189b962b660b81945ccee5bd6e75bbf22348c1ece286baeec6776e5cc66206f2b5de96cf0c8a0ca407e1"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000001002",
"organizationId": "0199dfe1-0000-7000-8000-000000001001",
"metadata": {
"version": 1,
"name": "Managed owner"
},
"status": "active",
"namespace": "eip155",
"address": "0x3333333333333333333333333333333333333333",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000001004",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"createdAt": "2026-10-15T02:57:32.345Z",
"updatedAt": "2026-10-15T02:57:32.345Z",
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "factory",
"factoryVersion": "2.0.0",
"implementationVersion": "v1.0.0",
"ownerAddress": "0x90C59223ac50061f5204826078944ec41bc56e0d",
"salt": "0"
}
},
"creator": {
"organizationMember": {
"id": "0199dfe1-0000-7000-8000-000000001005",
"userId": "0199dfe1-0000-7000-8000-000000001006",
"organizationId": "0199dfe1-0000-7000-8000-000000001001",
"organizationRoleId": "0199dfe1-0000-7000-8000-000000001007",
"joinedAt": "2026-10-15T02:57:32.244Z"
},
"user": {
"id": "0199dfe1-0000-7000-8000-000000001006",
"email": "0199dfe1-0000-7000-8000-000000001008@example.com",
"emailVerified": true,
"metadata": {
"version": 1
},
"lastLoginAt": "2026-10-15T02:57:32.211Z"
},
"organizationRole": {
"id": "0199dfe1-0000-7000-8000-000000001007",
"key": "owner",
"permissions": [
"organization:read",
"organization:update",
"member:read",
"member:update",
"member:remove",
"invitation:read",
"invitation:create",
"invitation:cancel",
"role:read",
"role:create",
"role:update",
"role:delete",
"billing:read",
"billing:update",
"billing:cancel",
"wallet:read",
"wallet:create",
"wallet:update",
"session-key:read",
"session-key:create",
"session-key:revoke",
"api-key:read",
"api-key:create",
"api-key:revoke",
"execution:read",
"mcp-authorization:read",
"mcp-authorization:create",
"mcp-authorization:revoke",
"cli-authorization:read",
"cli-authorization:create",
"cli-authorization:revoke"
],
"metadata": {
"version": 1,
"name": "Owner",
"description": "Organization owner with full access"
},
"type": "system",
"systemRoleId": "0199dfe1-0000-7000-8000-000000001009"
}
},
"installations": [
{
"id": "0199dfe1-0000-7000-8000-000000001010",
"chainId": "eip155:11155111",
"status": "installed",
"authorization": {
"version": 1,
"entityId": 94541820,
"signerAddress": "0xAB592704Fde287292b3a886Db80C0B6e7AC6DAdc",
"permissions": [
{
"type": "root"
}
],
"allowSignatures": false,
"validAfter": 1792033052,
"validUntil": 1792036652
},
"installTransactionHash": "0x2222222222222222222222222222222222222222222222222222222222222222",
"uninstallTransactionHash": null
}
]
}
```
The complete returned session retains its installation state. Its grants are revoked immediately and unsigned installation requests are cancelled. Installed or signed authority can keep the session `revoking`; a never-installed session can finish immediately.
## Remove installed networks [#remove-installed-networks]
For each remaining installed network:
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const result = await namera.sessionKeys.prepareOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000001000",
chainId: "eip155:11155111",
kind: "uninstall",
sponsor: true,
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000001011",
"namespace": "eip155",
"approval": "1claw",
"prepared": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"entryPointVersion": "0.7",
"entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"sponsorship": "none",
"context": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"account": "0x3333333333333333333333333333333333333333",
"block": {
"number": "0",
"hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "1970-01-01T00:00:00.000Z"
},
"calls": [
{
"to": "0x3333333333333333333333333333333333333333",
"value": "0",
"data": "0xabcd"
}
],
"userOperation": {
"nonce": "0",
"gas": {
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"paymasterVerificationGasLimit": "0",
"paymasterPostOpGasLimit": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0"
},
"paymaster": null
},
"simulation": {
"userOperation": {
"source": "eth_estimateUserOperationGas",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "1000000000",
"maxPriorityFeePerGas": "1"
},
"calls": {
"source": "viem.simulateCalls",
"results": [
{
"status": "success",
"returnData": "0x",
"gasUsed": "0"
}
],
"assetChanges": [],
"transfers": []
}
}
},
"userOperation": {
"sender": "0x3333333333333333333333333333333333333333",
"nonce": "0",
"callData": "0x",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0",
"signature": "0x"
},
"billing": {
"executionMeter": "execution.testnet",
"sponsorship": null
}
},
"expiresAt": "2026-10-15T03:02:34.211Z"
}
```
Preparation contains the stored removal calldata. Follow the [explicit approval flow](https://namera.ai/docs/sdk/guides/accounts/install-session-keys) and poll `getOperation()` until confirmed. A local signer can act outside Namera until its onchain authority is removed.
You may remove one network from an active session without revoking its other network installations. To retire the entire session, revoke server access and remove every installed network. Missing receipts are not proof of removal or failure; let reconciliation resolve signed work.
# Sign Messages
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/signing/sign-messages
Sign a text message with your account and an authorized session key.
Use `namera.sign()` with `type: "message"` to sign a UTF-8 string. Signing a
message does not submit a transaction.
## Before You Start [#before-you-start]
Set up [authentication](https://namera.ai/docs/sdk/authentication) and a session key installed
on **Base Sepolia**. The installation needs signature authority, and its API
signature policy must allow `message` signing.
See [Permissions](https://namera.ai/docs/sdk/permissions#message-and-typed-data-signing).
```sh
npm install @namera-ai/sdk
```
## Sign a Message [#sign-a-message]
Replace the IDs with your account and session key:
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
console.log(signed.data);
```
```json
{
"namespace": "eip155",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"chainId": "eip155:84532",
"account": "0x1111111111111111111111111111111111111111",
"signature": "0x0000000100111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111b",
"type": "message"
}
```
The response values are illustrative. Use the actual `signature` returned by
your request, with the original message, account, and network.
## Verify the Signature [#verify-the-signature]
```ts title="index.ts"
const verification = await namera.verifySignature({
namespace: "eip155",
walletId: signed.data.walletId,
chainId: signed.data.chainId,
type: "message",
message,
signature: signed.data.signature,
});
if (!verification.success) throw new Error(verification.error.message);
console.log(verification.data);
```
```json
{
"namespace": "eip155",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"chainId": "eip155:84532",
"account": "0x1111111111111111111111111111111111111111",
"valid": true,
"type": "message"
}
```
Check `verification.data.valid`, not just `success`. These are smart-account
signatures; use [Verify Signatures](https://namera.ai/docs/sdk/guides/signing/verify-signatures)
rather than comparing a recovered EOA address.
For structured payloads, use [Sign Typed Data](https://namera.ai/docs/sdk/guides/signing/sign-typed-data).
# Sign Typed Data
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/signing/sign-typed-data
Sign structured EIP-712 data with your account.
Use `namera.sign()` with `type: "typed-data"` for EIP-712 payloads. The domain,
types, primary type, and message together define what is signed.
## Before You Start [#before-you-start]
Use an [authenticated client](https://namera.ai/docs/sdk/authentication) and a session key
installed on **Base Sepolia** with signature authority. Its API signature
policy must allow `typed-data` and match any configured domain rules.
```sh
npm install @namera-ai/sdk
```
## Define the Payload [#define-the-payload]
This example signs a `Greeting` for your application. Replace the verifying
contract with your application's contract on Base Sepolia, and use the domain
and types expected by that application.
```ts title="index.ts"
import { NameraClient, type EvmTypedData } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const typedData = {
domain: {
name: "Namera Example",
version: "1",
chainId: 84532,
verifyingContract: "0x3333333333333333333333333333333333333333",
},
types: {
Greeting: [{ name: "contents", type: "string" }],
},
primaryType: "Greeting",
message: { contents: "Hello from Namera" },
} satisfies EvmTypedData;
```
The domain uses the numeric chain ID `84532`. The SDK request uses the network
identifier `eip155:84532`.
## Sign the Payload [#sign-the-payload]
Replace the account and session-key IDs with your own:
```ts title="index.ts"
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
type: "typed-data",
typedData,
});
if (!signed.success) throw new Error(signed.error.message);
console.log(signed.data);
```
```json
{
"namespace": "eip155",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"chainId": "eip155:84532",
"account": "0x1111111111111111111111111111111111111111",
"signature": "0x0000000100222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221b",
"type": "typed-data"
}
```
The signature above is illustrative. Keep the actual signature and the exact
payload you signed for [verification](https://namera.ai/docs/sdk/guides/signing/verify-signatures).
## Use Integer Values [#use-integer-values]
Typed-data messages must be JSON-compatible. For large integer fields such as
`uint256`, use decimal strings rather than JavaScript `bigint` values or
numbers that lose precision. This differs from transaction `value`, which
accepts a `bigint`.
## Match Your Signature Policy [#match-your-signature-policy]
When your session has typed-data rules, one rule must match the chain,
verifying contract, primary type, and any configured domain name and version.
Domain names and versions are case-sensitive.
These rules restrict the payload's domain and type, not the amounts inside a
permit or other authorization. Review the actual message before signing.
Signing returns a signature; it does not submit the payload to the target contract.
# Verify Signatures
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/signing/verify-signatures
Check a smart-account signature against its original message or typed data.
Use `verifySignature()` with the original payload, account ID, network, and
signature. Verification is read-only and does not need a `sessionKeyId`.
Your credential must still have access to the account.
## Verify a Message [#verify-a-message]
This runnable example signs a message, then verifies the returned signature.
Use [authentication](https://namera.ai/docs/sdk/authentication) and replace the IDs with an
account and session key configured for [message signing](https://namera.ai/docs/sdk/guides/signing/sign-messages).
```sh
npm install @namera-ai/sdk
```
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const walletId = "0199dfe1-0000-7000-8000-000000000001";
const sessionKeyId = "0199dfe1-0000-7000-8000-000000000002";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId,
sessionKeyId,
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
const verification = await namera.verifySignature({
namespace: "eip155",
walletId,
chainId: "eip155:84532",
type: "message",
message,
signature: signed.data.signature,
});
if (!verification.success) throw new Error(verification.error.message);
console.log(verification.data);
```
```json
{
"namespace": "eip155",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"chainId": "eip155:84532",
"account": "0x1111111111111111111111111111111111111111",
"valid": true,
"type": "message"
}
```
If you already have a signature, skip `sign()` and pass that signature to
`verifySignature()`. Preserve the original message exactly, including whitespace.
## Verify Typed Data [#verify-typed-data]
After [signing typed data](https://namera.ai/docs/sdk/guides/signing/sign-typed-data), add this
snippet to that example. It uses the existing `namera`, `typedData`, and successful
`signed` result from that page:
```ts title="index.ts"
const verification = await namera.verifySignature({
namespace: "eip155",
walletId: signed.data.walletId,
chainId: signed.data.chainId,
type: "typed-data",
typedData,
signature: signed.data.signature,
});
if (!verification.success) throw new Error(verification.error.message);
console.log(verification.data);
```
```json
{
"namespace": "eip155",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"chainId": "eip155:84532",
"account": "0x1111111111111111111111111111111111111111",
"valid": true,
"type": "typed-data"
}
```
Supply the same domain, types, primary type, and message that were signed.
Changing a field changes the payload being verified.
## Read the Outcome [#read-the-outcome]
`success: true` means the verification request completed. Only `data.valid: true`
means the signature was accepted for that account and payload. Treat
`valid: false` as an invalid signature; handle `success: false` as a request error.
Namera returns smart-account signatures. Recovering an EOA address from the signature is not a
substitute for checking the account's signature validation.
# Batch Transactions
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/transactions/batch-transactions
Submit multiple calls in one execution.
Put multiple calls in the `calls` array to submit them together. A batch uses
one account, one session key, and one network, with a single submission ID to track.
## Before You Start [#before-you-start]
Set up [authentication](https://namera.ai/docs/sdk/authentication). Your session key must be
installed on **Base Sepolia**, allow both recipients, and permit the combined
**0.002 ETH** transfer. Fund the account with **0.002 test ETH**.
```sh
npm install @namera-ai/sdk viem
```
## Submit a Batch [#submit-a-batch]
Replace the IDs and both recipients with your own. Calls are executed in array order.
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
import { parseEther } from "viem";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const batch = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
{
to: "0x4444444444444444444444444444444444444444",
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true,
});
if (!batch.success) throw new Error(batch.error.message);
console.log(batch.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "prepared",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
Every call must pass the selected session key's permissions and policies.
Native spending limits apply to the sum of all call values, not each transfer
individually. A batch cannot combine authority from different session keys.
## Combine Different Calls [#combine-different-calls]
The array can contain native transfers and
[encoded contract calls](https://namera.ai/docs/sdk/guides/transactions/interact-with-contracts).
For dependent calls, such as approval followed by a contract interaction, put
the prerequisite first and ensure both calls are permitted.
[Simulate the full batch](https://namera.ai/docs/sdk/guides/transactions/simulate-transactions)
before submitting it, then
[track its submission](https://namera.ai/docs/sdk/guides/transactions/track-transactions).
# Handle Retries and Recovery
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/transactions/handle-retries-and-recovery
Recover from interrupted requests without submitting duplicate transactions.
When a request fails, first determine whether you have a `submissionId`.
If you do, check that submission. A new `executions.execute()` call creates a
new operation, even when its parameters are identical.
## Understand Automatic Retries [#understand-automatic-retries]
During `execute()`, the SDK retries transient preparation and completion
failures up to three times each, with exponential backoff starting at 100 ms.
Preparation retries reuse the same idempotency key. Completion retries reuse
the same submission and, when supplied, the same signature.
Eligible failures are transport errors, HTTP 408, HTTP 5xx, and the declared
`InternalServerError`. Policy denials, authentication failures, rate limits, and
other declared business errors are not automatically retried.
These retries happen **inside one call**. There is no public idempotency-key
option on `execute()` to deduplicate separate calls or process restarts.
A lost response does not prove that the transaction failed. Wrapping `execute()` in a retry loop
can send the same transfer twice.
## Save the Submission ID [#save-the-submission-id]
After a successful `execute()` result, save `result.data.submissionId` with your
application's job or payment record before marking that work as submitted.
Keep the intended account, network, recipient, and amount with the same record.
Persist this in durable storage, not just a process variable or console log.
See [Execute a Transaction](https://namera.ai/docs/sdk/reference/executions/execute) for the
request and full submission response.
Prevent concurrent workers from executing the same application job. An
application-level job ID helps coordinate your workers; it is not a Namera
idempotency key and does not close the gap between submission and saving its ID.
## Resume Status Checks [#resume-status-checks]
Install `@namera-ai/sdk`, set `NAMERA_API_KEY`, and replace the example ID with
the submission saved for your job. This Node.js example checks for up to one
minute. It retries failed **reads**, never the transaction:
```ts title="index.ts"
import { setTimeout } from "node:timers/promises";
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const submissionId = "0199dfe1-0000-7000-8000-000000000003";
const deadline = Date.now() + 60_000;
let settled = false;
while (Date.now() < deadline) {
const result = await namera.executions.getStatus(submissionId);
let delay = 3000;
if (!result.success) {
const { error } = result;
if (error.kind === "api" && error.cause._tag === "RateLimitExceeded") {
delay = Math.max(delay, error.cause.retryAfterSeconds * 1000);
} else if (
error.kind !== "network" &&
!(error.kind === "api" && error.cause._tag === "InternalServerError") &&
!(error.status === 408 || (error.status !== null && error.status >= 500))
) {
throw new Error(error.message);
}
} else {
console.log(result.data);
if (result.data.status === "confirmed" || result.data.status === "failed") {
settled = true;
break;
}
}
if (Date.now() + delay >= deadline) break;
await setTimeout(delay);
}
if (!settled) {
console.log("Status is unresolved. Keep the submission ID and check again later.");
}
```
A pending response has this shape:
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "submitted",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
The time limit stops new checks; it does not cancel an in-flight request or the
transaction. If a rate-limit delay exceeds the remaining time, wait that delay
before resuming in a later run.
- **`reserved`, `prepared`, or `submitted`**: keep tracking the same ID.
- **`confirmed`**: store the returned execution and mark the job complete.
- **`failed`**: stop polling and investigate before intentionally starting a
replacement operation.
See [Get Submission Status](https://namera.ai/docs/sdk/reference/executions/get-submission-status)
for all response variants. `getStatus()` itself does not retry automatically;
the example above supplies a bounded policy for read failures.
## Recover Without a Submission ID [#recover-without-a-submission-id]
If `execute()` fails before returning an ID, or your process stops before saving
it, mark the application job as **unresolved**, not ready to retry. The error
result does not expose the internally prepared submission ID.
Inspect [execution history](https://namera.ai/docs/sdk/reference/executions/list-executions) and
[execution details](https://namera.ai/docs/sdk/reference/executions/get-execution) for a matching
confirmed operation. Compare the account, network, calls, and timing. Identical
transfers can be legitimate, so matching values alone do not uniquely identify
your job.
History contains confirmed executions only. An empty history result does not
rule out a pending submission. If you cannot establish the outcome, keep the
job unresolved and reconcile it before allowing another execution.
## Fix Errors Before Resubmitting [#fix-errors-before-resubmitting]
Correct invalid inputs, credentials, permissions, or funding before starting a
replacement operation. For a paused network, wait for it to be enabled again.
Do not treat a transport failure as evidence that these checks rejected the
original transaction.
For rate limits, respect `retryAfterSeconds`; see
[Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors). The same
caution applies to signing: a lost `sign()` response is not a reason to repeat
it automatically, since another call can create another billable signing operation.
# Interact with Contracts
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/transactions/interact-with-contracts
Encode and execute a smart-contract function call.
Pass a contract address and encoded function call to `executions.execute()`.
The contract receives the call from your Namera account.
## Before You Start [#before-you-start]
Use an [authenticated client](https://namera.ai/docs/sdk/authentication) and a session key
installed on **Base Sepolia**. Its permissions must allow the target contract
and function.
```sh
npm install @namera-ai/sdk viem
```
## Call a Function [#call-a-function]
This example calls `setGreeting(string)` on a contract you have deployed.
Replace the IDs and contract address with your own, and use the ABI of the
contract you are calling.
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
import { encodeFunctionData, parseAbi } from "viem";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const abi = parseAbi(["function setGreeting(string greeting)"]);
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x3333333333333333333333333333333333333333",
value: 0n,
data: encodeFunctionData({
abi,
functionName: "setGreeting",
args: ["Hello from Namera"],
}),
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "prepared",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
The response identifies the submission, not the function's return value.
[Track it](https://namera.ai/docs/sdk/guides/transactions/track-transactions) to confirm execution.
## Send ETH with a Call [#send-eth-with-a-call]
For a **payable** function, set the call's `value` with `parseEther`:
```ts title="index.ts"
import { parseEther } from "viem";
const value = parseEther("0.001");
```
Use this value in place of `0n` only when the target function accepts ETH.
The `setGreeting` example above is not payable. The account needs enough ETH
and the session key must allow the native transfer as well as the function call.
Before submitting a new contract interaction,
[simulate the transaction](https://namera.ai/docs/sdk/guides/transactions/simulate-transactions).
# Simulate Transactions
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/transactions/simulate-transactions
Preview calls and check installed permissions before submitting.
Use `executions.simulate()` to inspect a transaction without signing or
submitting it. Simulation does not reserve billing allowance.
## Simulate a Transfer [#simulate-a-transfer]
Use an [authenticated client](https://namera.ai/docs/sdk/authentication) and a session key
installed on **Base Sepolia**. The account needs the test ETH being transferred.
Replace the example IDs and recipient with your own.
```sh
npm install @namera-ai/sdk viem
```
```ts title="index.ts"
import { NameraClient, type SimulateExecutionRequest } from "@namera-ai/sdk";
import { parseEther } from "viem";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const request = {
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
} satisfies SimulateExecutionRequest;
const simulation = await namera.executions.simulate(request);
if (!simulation.success) throw new Error(simulation.error.message);
console.log(simulation.data);
```
```json
{
"namespace": "eip155",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"chainId": "eip155:84532",
"account": "0x1111111111111111111111111111111111111111",
"callsSucceeded": true,
"simulation": {
"userOperation": {
"source": "eth_estimateUserOperationGas",
"callGasLimit": "50000",
"verificationGasLimit": "100000",
"preVerificationGas": "50000",
"maxFeePerGas": "1000000000",
"maxPriorityFeePerGas": "1000000"
},
"calls": {
"source": "viem.simulateCalls",
"results": [{ "status": "success", "returnData": "0x", "gasUsed": "21000" }],
"assetChanges": [],
"transfers": [
{
"callIndex": 0,
"from": "0x1111111111111111111111111111111111111111",
"to": "0x2222222222222222222222222222222222222222",
"value": "1000000000000000"
}
]
}
},
"allowed": true,
"sessionKeyId": "0199dfe1-0000-7000-8000-000000000002"
}
```
Gas estimates are illustrative. Quantities shown as decimal strings in JSON
are `bigint` values in the SDK.
## Read the Result [#read-the-result]
- `callsSucceeded` reports whether the simulated calls succeeded.
- `allowed` reports point-in-time eligibility for the selected session key.
- `simulation.calls` contains per-call results, detected asset changes, and native transfers.
If simulation itself fails, the SDK returns `success: false`; handle it as an
[error](https://namera.ai/docs/sdk/handling-results-and-errors).
## Execute the Same Calls [#execute-the-same-calls]
After reviewing the result, submit the same request with sponsorship enabled:
```ts title="index.ts"
if (!simulation.data.callsSucceeded || !simulation.data.allowed) {
throw new Error("Review the simulation before executing.");
}
const execution = await namera.executions.execute({ ...request, sponsor: true });
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "prepared",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
Balances, permissions, and available budgets can change after simulation. Execution checks them
again. The second snippet submits a real testnet transaction.
Next, [track the submission](https://namera.ai/docs/sdk/guides/transactions/track-transactions).
# Sponsor Gas
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/transactions/sponsor-gas
Choose sponsored execution or pay gas from your account.
Namera sponsors gas by default. Set `sponsor: false` to pay gas from your account
instead. The same execution method supports both options.
## Set Up the Transfer [#set-up-the-transfer]
Set up [authentication](https://namera.ai/docs/sdk/authentication) and a session key installed on
**Base Sepolia** with permission to send **0.001 test ETH**. Replace the IDs and
recipient below with your own.
```sh
npm install @namera-ai/sdk viem
```
```ts title="index.ts"
import { NameraClient, type ExecuteRequest } from "@namera-ai/sdk";
import { parseEther } from "viem";
const transfer = {
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
} satisfies ExecuteRequest;
```
Choose one of the following options. Each example submits a new transfer.
## Use Sponsored Gas [#use-sponsored-gas]
```ts title="index.ts"
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const sponsored = await namera.executions.execute({ ...transfer, sponsor: true });
if (!sponsored.success) throw new Error(sponsored.error.message);
console.log(sponsored.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "prepared",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
Omitting `sponsor` has the same effect as `sponsor: true`. Sponsorship is subject
to your workspace's plan and available allowance.
The account still needs the assets being transferred. Installed session-key permissions, including
gas limits, still apply.
## Pay Gas from Your Account [#pay-gas-from-your-account]
Set `maxGasCostWei` on the client and pass `sponsor: false` to the execution.
Here, **0.0001 ETH** is the maximum gas cost you approve for the operation:
```ts title="index.ts"
const selfFundedClient = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
maxGasCostWei: parseEther("0.0001"),
});
const selfFunded = await selfFundedClient.executions.execute({
...transfer,
sponsor: false,
});
if (!selfFunded.success) throw new Error(selfFunded.error.message);
console.log(selfFunded.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000011",
"status": "prepared",
"userOperationHash": "0x2222222222222222222222222222222222222222222222222222222222222222"
}
```
Fund the account with enough ETH on the selected network for the transfer and
gas. The ceiling is not a gas price or an extra payment. The SDK rejects a
prepared operation that exceeds it; choose a ceiling you are willing to pay.
Self-funded execution does not use sponsored-gas credits, but still counts
toward execution usage.
With either option, [track the submission](https://namera.ai/docs/sdk/guides/transactions/track-transactions)
to read the final outcome.
# Track Transactions
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/transactions/track-transactions
Follow a submission to confirmation and read its execution record.
Save the `submissionId` returned by `executions.execute()`. Use it to check
progress without submitting the transaction again.
## Check a Submission [#check-a-submission]
Use your [API key](https://namera.ai/docs/sdk/authentication) and replace the example submission
ID with the one returned by your execution:
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const submissionId = "0199dfe1-0000-7000-8000-000000000003";
const status = await namera.executions.getStatus(submissionId);
if (!status.success) throw new Error(status.error.message);
console.log(status.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "submitted",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
## Follow the Status [#follow-the-status]
- **`reserved`**: waiting for a signature.
- **`prepared`**: signed and queued for broadcast.
- **`submitted`**: observed by the bundler; not yet confirmed.
- **`confirmed`**: completed successfully, with an execution record.
- **`failed`**: did not complete successfully.
Poll the same submission until it reaches a terminal status. This example
checks every three seconds for up to one minute:
```ts title="index.ts"
for (let attempt = 0; attempt < 20; attempt++) {
const latest = await namera.executions.getStatus(submissionId);
if (!latest.success) throw new Error(latest.error.message);
console.log(latest.data);
if (latest.data.status === "confirmed" || latest.data.status === "failed") break;
await new Promise((resolve) => setTimeout(resolve, 3000));
}
```
If it is still pending, keep the ID and check again later. Reaching the polling
limit does not mean the transaction failed.
Each new `execute()` call starts a new operation. Poll `getStatus()` instead. A failed or missing
response alone does not prove that no transaction was submitted.
## Read a Confirmed Execution [#read-a-confirmed-execution]
Once confirmed, `data.execution` contains the calls, transaction hash, and
receipt. For the 0.001 ETH transfer, a confirmed response has this shape:
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "confirmed",
"execution": {
"id": "0199dfe1-0000-7000-8000-000000000012",
"executionSubmissionId": "0199dfe1-0000-7000-8000-000000000003",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"sessionKeyGrantId": "0199dfe1-0000-7000-8000-000000000013",
"namespace": "eip155",
"data": {
"version": 1,
"chainId": "eip155:84532",
"calls": [
{
"to": "0x2222222222222222222222222222222222222222",
"value": "1000000000000000",
"data": "0x"
}
],
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"transactionHash": "0x5555555555555555555555555555555555555555555555555555555555555555",
"receipt": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:84532",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"transactionHash": "0x5555555555555555555555555555555555555555555555555555555555555555",
"blockHash": "0x6666666666666666666666666666666666666666666666666666666666666666",
"blockNumber": "32000000",
"sender": "0x1111111111111111111111111111111111111111",
"nonce": "0",
"entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"paymaster": null,
"actualGasCost": "0",
"actualGasUsed": "120000",
"success": true,
"reason": null
}
},
"createdAt": "2026-10-11T09:10:00.000Z"
}
}
```
Hashes and receipt values are illustrative. Quantities shown as decimal strings
in JSON are `bigint` values in the SDK.
Use `execution.data.transactionHash` to look up the transaction on the network's
block explorer. The `userOperationHash` identifies the account operation and is
not the transaction hash.
## Read Execution History [#read-execution-history]
Filter confirmed executions by account or session key:
```ts title="index.ts"
const history = await namera.executions.list({
walletId: "0199dfe1-0000-7000-8000-000000000001",
});
if (!history.success) throw new Error(history.error.message);
console.log(history.data);
```
```json
{
"items": [
{
"details": {
"id": "0199dfe1-0000-7000-8000-000000000012",
"namespace": "eip155",
"chainId": "eip155:84532",
"transactionHash": "0x5555555555555555555555555555555555555555555555555555555555555555",
"createdAt": "2026-10-11T09:10:00.000Z"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000000001",
"namespace": "eip155",
"address": "0x1111111111111111111111111111111111111111",
"metadata": {
"version": 1,
"name": "Example account",
"logo": { "type": "emoji", "value": "π" },
"description": "SDK test account"
}
},
"sessionKey": {
"id": "0199dfe1-0000-7000-8000-000000000002",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Example session",
"logo": { "type": "emoji", "value": "π" },
"description": "Send test ETH on Base Sepolia"
}
},
"actorType": "api-key"
}
],
"nextCursor": null
}
```
When `nextCursor` is not `null`, pass it as `cursor` with the same filters to get
the next page. History contains confirmed executions; use `getStatus()` for
pending or failed submissions.
# Transfer Assets
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/guides/transactions/transfer-assets
Send native tokens or ERC-20 tokens from your account.
Use `executions.execute()` to transfer assets. The examples below send ETH and
an ERC-20 token on **Base Sepolia**.
## Before You Start [#before-you-start]
Set up [authentication](https://namera.ai/docs/sdk/authentication) and choose an
[account and session key](https://namera.ai/docs/sdk/accounts-and-session-keys). The key must be
installed on Base Sepolia and allow the transfer. Fund the account with the
asset you want to send.
```sh
npm install @namera-ai/sdk viem
```
Replace the example account ID, session-key ID, and recipient with your own:
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({ apiKey: process.env.NAMERA_API_KEY! });
const walletId = "0199dfe1-0000-7000-8000-000000000001";
const sessionKeyId = "0199dfe1-0000-7000-8000-000000000002";
const recipient = "0x2222222222222222222222222222222222222222";
```
Choose one of the transfer examples below and add it after this setup.
## Transfer Native Tokens [#transfer-native-tokens]
This sends **0.001 test ETH**. Allow the recipient and a native-token allowance
that covers the transfer in your session key's permissions.
```ts title="index.ts"
import { parseEther } from "viem";
const transfer = await namera.executions.execute({
namespace: "eip155",
walletId,
sessionKeyId,
chainId: "eip155:84532",
calls: [{ to: recipient, value: parseEther("0.001"), data: "0x" }],
sponsor: true,
});
if (!transfer.success) throw new Error(transfer.error.message);
console.log(transfer.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "prepared",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
## Transfer ERC-20 Tokens [#transfer-erc-20-tokens]
Call the token contract's `transfer` function. This example sends **1 token**
with **6 decimals**. Replace the token address and decimals with those of your
token on Base Sepolia. The session key must allow that token transfer.
```ts title="index.ts"
import { encodeFunctionData, erc20Abi, parseUnits } from "viem";
const tokenAddress = "0x3333333333333333333333333333333333333333";
const decimals = 6;
const tokenTransfer = await namera.executions.execute({
namespace: "eip155",
walletId,
sessionKeyId,
chainId: "eip155:84532",
calls: [
{
to: tokenAddress,
value: 0n,
data: encodeFunctionData({
abi: erc20Abi,
functionName: "transfer",
args: [recipient, parseUnits("1", decimals)],
}),
},
],
sponsor: true,
});
if (!tokenTransfer.success) throw new Error(tokenTransfer.error.message);
console.log(tokenTransfer.data);
```
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000011",
"status": "prepared",
"userOperationHash": "0x2222222222222222222222222222222222222222222222222222222222222222"
}
```
`to` is the token contract; the recipient and amount are encoded in `data`.
`value: 0n` means the call sends no native ETH.
Sponsorship covers gas, not the assets being sent. Your account must hold the ETH or tokens you
are transferring.
These are illustrative submission values. Use the `submissionId` returned by
your request to [track the transaction](https://namera.ai/docs/sdk/guides/transactions/track-transactions).
`prepared` means queued, not confirmed.
# Handling Results and Errors
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/handling-results-and-errors
Read SDK results, handle failures, and check transaction outcomes.
SDK requests return a result with `success`, `data`, and `error`. Check
`success` before using the response data.
## Read a Result [#read-a-result]
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
const wallets = await namera.wallets.list();
if (wallets.success) {
console.log(wallets.data);
} else {
console.error(wallets.error.message);
}
```
On success, `data` contains the response and `error` is `null`. On failure,
`data` is `null` and `error` describes what went wrong.
## Handle an API Error [#handle-an-api-error]
Use `error.kind` to identify the category. For API errors, `error.cause` retains
the endpoint's typed error details. For example, a rate-limit error includes
the number of seconds to wait:
```ts title="index.ts"
const sessions = await namera.sessionKeys.list();
if (sessions.success) {
console.log(sessions.data);
} else if (sessions.error.kind === "api" && sessions.error.cause._tag === "RateLimitExceeded") {
console.error(`Try again in ${sessions.error.cause.retryAfterSeconds} seconds.`);
} else {
console.error(sessions.error.message);
}
```
### Error Categories [#error-categories]
- **`api`**: Namera rejected the request. Check `cause` and, when provided,
`code` for the specific reason.
- **`contract`**: an input or response does not match the expected schema.
Check IDs and request fields; if the inputs are valid, check your SDK version.
- **`network`**: the API could not be reached. Check connectivity before retrying.
- **`signer`**: signing could not proceed or a prepared operation failed validation.
Follow the error message; do not bypass validation.
- **`unexpected`**: another failure occurred. Keep the error details for diagnosis.
Use error tags or codes for program logic, not message text. `error.status`
can be `null`, including for API errors.
## Check the Transaction Outcome [#check-the-transaction-outcome]
A successful `execute()` request does not mean the transaction is confirmed.
Use its `submissionId` to check progress. Replace the example ID with the one
returned by your execution:
```ts title="index.ts"
const status = await namera.executions.getStatus("0199dfe1-0000-7000-8000-000000000003");
if (!status.success) throw new Error(status.error.message);
console.log(status.data);
if (status.data.status === "confirmed") {
console.log(status.data.execution);
}
```
Check the same submission after a short delay while its status is `reserved`,
`prepared`, or `submitted`. Stop polling on `confirmed` or `failed`.
## Retry Carefully [#retry-carefully]
The execution flow already retries transient preparation and completion
failures using the same operation. It does not retry policy denials.
Calling `execute()` again starts a new operation. Once you have a submission ID,
check that submission instead of resending the transaction. A network failure
alone does not prove that nothing was submitted.
For a complete transaction walkthrough, see [Getting Started](https://namera.ai/docs/sdk/getting-started).
# Overview
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk
Build with Namera in TypeScript.
The Namera SDK lets your backend provision accounts and session keys with explicit
workspace permissions, then send transactions and sign within session authority.
## Quick Examples [#quick-examples]
Create a client with your API key:
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
### Create an Account [#create-an-account]
With an API key explicitly granted `wallet:create`:
```ts title="index.ts"
const result = await namera.wallets.create({
namespace: "eip155",
metadata: { version: 1, name: "Backend treasury" },
owner: { type: "namera-managed", provider: "1claw" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
Continue with [session creation and explicit installation](https://namera.ai/docs/sdk/guides/accounts/create-session-keys).
### List Accounts [#list-accounts]
```ts title="index.ts"
const result = await namera.wallets.list();
if (result.success) {
console.log(result.data);
}
```
### Sign a Message [#sign-a-message]
Use the `session` selected in [Getting Started](https://namera.ai/docs/sdk/getting-started#list-session-keys).
```ts title="index.ts"
const result = await namera.sign({
namespace: "eip155",
walletId: session.walletId,
sessionKeyId: session.id,
chainId: "eip155:84532",
type: "message",
message: "Hello from Namera",
});
if (result.success) {
console.log(result.data);
}
```
The session needs onchain signature authority and an API signature policy that
allows this message on Base Sepolia.
### Execute a Transaction [#execute-a-transaction]
Use the `session` selected in [Getting Started](https://namera.ai/docs/sdk/getting-started#list-session-keys).
Replace the example recipient with the wallet allowed by that key.
This sends 0.001 test ETH on Base Sepolia.
```ts title="index.ts"
import { parseEther } from "viem";
const result = await namera.executions.execute({
namespace: "eip155",
walletId: session.walletId,
sessionKeyId: session.id,
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true,
});
if (result.success) {
console.log(result.data.submissionId);
}
```
Follow [Getting Started](https://namera.ai/docs/sdk/getting-started#execute-a-transaction) for
funding, permissions, and checking the submission status.
## What You Can Build [#what-you-can-build]
## Start Building [#start-building]
[Install the SDK](https://namera.ai/docs/sdk/installation), then follow
[Getting Started](https://namera.ai/docs/sdk/getting-started) to connect your workspace.
# Installation
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/installation
Add the Namera SDK to your project.
## Requirements [#requirements]
Use **Node.js 24.14+**, or a modern browser with Fetch and Web Crypto.
## Install [#install]
```sh
npm install @namera-ai/sdk
```
```sh
pnpm add @namera-ai/sdk
```
```sh
yarn add @namera-ai/sdk
```
```sh
bun add @namera-ai/sdk
```
Continue to [Getting Started](https://namera.ai/docs/sdk/getting-started) to create a client and
make your first request.
# Permissions
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/permissions
Understand what your session key is allowed to execute and sign.
A valid credential is only the first requirement. Your application also needs
access to a session key whose permissions allow execution or signing. Workspace
management is a separate, explicitly issued authority.
## Workspace management permissions [#workspace-management-permissions]
In **Settings β Workspace β API keys**, explicitly select the permissions your
backend needs. Existing keys have none. Permissions cover all existing and future
accounts and sessions in the keyβs workspace, never another workspace.
| Permission | Allows |
| ----------------------- | --------------------------------------------------------------- |
| `wallet:read` | Read all workspace accounts and their public owner descriptors. |
| `wallet:create` | Create managed or passkey-owned accounts. |
| `session-key:read` | Read all workspace sessions and this actorβs owner operations. |
| `session-key:create` | Create sessions on any workspace account. |
| `session-key:install` | Explicitly approve a stored session installation. |
| `session-key:uninstall` | Explicitly approve removal of a network installation. |
| `session-key:revoke` | Revoke a sessionβs Namera access and grants. |
Only users holding the corresponding management authority may issue it. Keys do
not inherit their creatorβs complete role and cannot issue other keys or expand
their own permissions. Create a replacement key to change permissions.
A key with session creation and installation authority can grant itself full
control of managed accounts. Reserve these permissions for trusted backend wallet
administration. API-key permission does not replace a passkey ownerβs signature.
Creating a session grants its creating API-key actor access; management access
alone does not grant execution access to pre-existing sessions.
Passkey registration also requires an exact application origin allowlisted at
key issuance. Keep the API key on your authenticated backend and bind ceremonies
and operation approvals to your application users.
See [account management guides](https://namera.ai/docs/sdk/guides/accounts/create-accounts).
## What Allows a Transaction [#what-allows-a-transaction]
Before executing, check that:
- Your API key or OAuth authorization has a grant to the selected session key.
- The key is active and its installation is confirmed on the target network.
- The installation is within its validity period and allows the recipient,
contract calls, and amounts you want to use.
Configure these in the [Namera dashboard](https://dashboard.namera.ai).
For a **0.001 ETH** transfer, allow the recipient and a native-token allowance
that covers the transfer, then approve the installation on that network.
## Onchain Permissions and API Policies [#onchain-permissions-and-api-policies]
**Onchain permissions** are approved by the account owner and enforced by the
account's contracts. They define transaction authority, including allowed
targets, functions, spending allowances, and validity periods.
**API policies** govern delegated signatures through Namera: signature type,
allowed networks, and validity windows. Transaction spending and gas restrictions
come from installed onchain permissions. All applicable policies must pass; one
policy cannot override another denial.
An API policy cannot allow a transaction that the onchain permissions reject. API policies apply
to requests through Namera, not calls made outside it.
## Inspect a Session Key [#inspect-a-session-key]
Replace the example ID with the session key you plan to use:
```ts title="index.ts"
import { NameraClient } from "@namera-ai/sdk";
const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
const result = await namera.sessionKeys.get("0199dfe1-0000-7000-8000-000000000002");
if (!result.success) throw new Error(result.error.message);
const session = result.data;
console.log(result.data);
```
Read `policies` for API restrictions. Each entry in `installations` includes its
`chainId`, `status`, and approved `authorization`. A usable installation has
status `installed`; also check its validity period and permissions.
## Check a Call Before Sending [#check-a-call-before-sending]
Install `viem` if you have not already, then simulate with the same account,
session key, network, and calls you intend to execute:
```sh
npm install viem
```
```ts title="index.ts"
import { parseEther } from "viem";
const simulation = await namera.executions.simulate({
namespace: "eip155",
walletId: session.walletId,
sessionKeyId: session.id,
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
});
if (!simulation.success) throw new Error(simulation.error.message);
console.log(simulation.data);
```
Replace the recipient with the address allowed by your key. Simulation does not
submit a transaction or reserve billing allowance. Review the call results;
balances, installed permissions and available allowance can change before execution.
## Message and Typed Data Signing [#message-and-typed-data-signing]
Signing needs explicit signature authority in the installation
(`allowSignatures`) and an API signature policy permitting the requested type:
`message` or `typed-data`. Transaction permissions alone do not enable signing.
Typed-data policies can restrict the chain, verifying contract, primary type,
and domain. They do not limit the amounts inside a signed message.
Transaction spending limits and expiry do not constrain onchain signature authority. Uninstall
that authority onchain to revoke it.
Next, choose a [supported network](https://namera.ai/docs/sdk/supported-networks).
# wallets.create
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/accounts/create-account
Create a 1Claw-managed or passkey-owned smart account.
`namera.wallets.create()` create a 1Claw-managed or passkey-owned smart account.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.create({
namespace: "eip155",
metadata: { version: 1, name: "Provisioned account" },
owner: { type: "namera-managed", provider: "1claw" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns the complete account, including its ID, address, public owner descriptor, reconstruction data, and timestamps.
```json
{
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000006",
"metadata": {
"version": 1,
"name": "Provisioned account"
},
"status": "active",
"namespace": "eip155",
"address": "0x3333333333333333333333333333333333333333",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000008",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"createdAt": "2026-10-15T02:39:05.250Z",
"updatedAt": "2026-10-15T02:39:05.250Z",
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "factory",
"factoryVersion": "2.0.0",
"implementationVersion": "v1.0.0",
"ownerAddress": "0x52e7f17258368d7f9Ebd7bDf8d6869Bc4759aBA1",
"salt": "0"
}
}
```
## Parameters [#parameters]
### namespace [#namespace]
Type: `"eip155"`. Required. The implemented chain namespace.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.create({
namespace: "eip155", // [!code focus]
metadata: { version: 1, name: "Provisioned account" },
owner: { type: "namera-managed", provider: "1claw" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### metadata [#metadata]
Type: `object`. Required. Account display metadata. `version` is `1`; `name` identifies the account in the dashboard. Optional `description` and `logo` follow the account metadata schema.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.create({
namespace: "eip155",
metadata: { version: 1, name: "Provisioned account" }, // [!code focus]
owner: { type: "namera-managed", provider: "1claw" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### owner [#owner]
Type: `object`. Required. Select the account owner. Managed owners use `{ type: "namera-managed", provider: "1claw" }`. Passkey owners use `{ type: "passkey", verificationId, response }` from a registration ceremony initiated by this credential. See the [account creation guide](https://namera.ai/docs/sdk/guides/accounts/create-accounts).
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.create({
namespace: "eip155",
metadata: { version: 1, name: "Provisioned account" },
owner: { type: "namera-managed", provider: "1claw" }, // [!code focus]
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
For a passkey owner, your authenticated backend calls this function with its stored verification ID and the browserβs registration response:
```ts title="index.ts"
import { namera } from "./client";
import type { CreateWalletRequest } from "@namera-ai/sdk";
export async function createPasskeyAccount(
verificationId: string,
response: Extract["response"],
) {
const result = await namera.wallets.create({
namespace: "eip155",
metadata: { version: 1, name: "Customer account" },
owner: { type: "passkey", verificationId, response }, // [!code focus]
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
}
```
#### owner.verificationId [#ownerverificationid]
Type: `string`. Required for passkey ownership. The one-time registration ID returned by `wallets.createPasskeyRegistrationOptions()`. Keep it bound to your authenticated application user on your backend.
#### owner.response [#ownerresponse]
Type: `PasskeyRegistrationResponse`. Required for passkey ownership. The browserβs complete WebAuthn registration response. Namera verifies the challenge, origin, RP ID, expiry, and initiating actor.
## Behavior and errors [#behavior-and-errors]
The API key needs `wallet:create`. Accounts belong to the credentialβs workspace. API keys do not gain account owner signing authority from creation alone. Managed creation retries transient failures with one SDK-generated idempotency key; a new method call starts a new request. Passkey creation is not automatically retried because registration is single-use. Creation does not deploy the smart account or install sessions. Billing limits and provider availability still apply. `MANAGEMENT_PERMISSION_DENIED` indicates authority was removed before admission. A provider result that requires recovery must not be blindly retried as a new request.
# wallets.createPasskeyRegistrationOptions
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/accounts/create-passkey-registration-options
Start a one-time passkey account registration.
`namera.wallets.createPasskeyRegistrationOptions()` start a one-time passkey account registration.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.createPasskeyRegistrationOptions({
origin: "https://app.example.com",
user: { name: "Customer", displayName: "Customer" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns `verificationId`, browser-ready WebAuthn `options`, and `expiresAt`. The credentialβs allowed origin determines the RP ID.
```json
{
"verificationId": "0199dfe1-0000-7000-8000-000000000022",
"options": {
"challenge": "OuAZdeWe1cPGP8if-E91tdEwtCgFVy68KEuEyXdtaIY",
"rp": {
"id": "app.example.com",
"name": "Namera"
},
"user": {
"id": "MDFhMTNkNmQtNzZkYi03NTUzLWE4M2QtMTFhMzRkNWJhNjFm",
"name": "Customer",
"displayName": "Customer"
},
"pubKeyCredParams": [
{
"alg": -7,
"type": "public-key"
}
],
"timeout": 300000,
"excludeCredentials": [],
"authenticatorSelection": {
"residentKey": "required",
"requireResidentKey": true,
"userVerification": "required"
},
"hints": [],
"attestation": "none",
"extensions": {
"credProps": true
}
},
"expiresAt": "2026-10-15T02:44:06.347Z"
}
```
## Parameters [#parameters]
### origin [#origin]
Type: `string`. Required. Exact origin of the application where the browser creates the credential. A human must approve it in this API keyβs passkey-origin allowlist when issuing the key. HTTPS is required except HTTP localhost/127.0.0.1 development origins. Paths, query strings, fragments, and credentials are rejected.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.createPasskeyRegistrationOptions({
origin: "https://app.example.com", // [!code focus]
user: { name: "Customer", displayName: "Customer" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### user [#user]
Type: `object`. Required. Application user labels for the browser prompt. `name` and `displayName` must be nonempty strings. These labels are not Namera membership or authorization. Your backend must bind the ceremony to its own authenticated application user.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.createPasskeyRegistrationOptions({
origin: "https://app.example.com",
user: { name: "Customer", displayName: "Customer" }, // [!code focus]
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Behavior and errors [#behavior-and-errors]
Requires `wallet:create` and an allowlisted origin. Keep the API key on your backend; send only the registration options to the browser. Ceremonies from the same API key are independent, so multiple application users can register concurrently. Registration preparation is not automatically retried. The response does not create an account; submit the browser response through `wallets.create()`. Never accept an arbitrary verification ID from a different application user.
# Get Account
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/accounts/get-account
Read one account by its ID.
`namera.wallets.get(walletId)` returns an account available to your credential.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.get("0199dfe1-0000-7000-8000-000000000001");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
- **`id`** (`string`): Account ID.
- **`organizationId`** (`string`): Owning organization ID.
- **`metadata`** (`object`): version and name, with optional logo and description.
- **`status`** (`"active" | "frozen" | "archived"`): Account lifecycle status.
- **`namespace`** (`"eip155"`): Chain namespace.
- **`address`** (`` `0x${string}` ``): Smart-account address.
- **`owner`** (`object`): Public signing-key identity, custody, algorithm, and provider-specific protection details.
- **`implementation`** (`"alchemy-modular-v2"`): Smart-account implementation.
- **`data`** (`object`): Account configuration, discriminated by validatorType and accountMode. Includes deployment and version fields.
- **`createdAt`** (`DateTime.Utc`): Creation time.
- **`updatedAt`** (`DateTime.Utc`): Last update time.
### Example Response [#example-response]
```json
{
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"metadata": {
"version": 1,
"name": "Example account",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "SDK test account"
},
"status": "active",
"namespace": "eip155",
"address": "0x1111111111111111111111111111111111111111",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000005",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "7702",
"delegationVersion": "v1.1.0"
},
"createdAt": "2026-10-11T09:00:00.000Z",
"updatedAt": "2026-10-11T09:00:00.000Z"
}
```
## Parameters [#parameters]
### walletId [#walletid]
- **Type:** `string`
- **Required**
The account UUID returned by `wallets.list()` or `wallets.get()`. Pass its `id`,
not its onchain `address`. The account must be accessible to the clientβs credential.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.get("0199dfe1-0000-7000-8000-000000000001"); // [!code focus]
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Errors [#errors]
`WALLET_NOT_FOUND` means the account does not exist or is not available to your credential. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors)
for authentication, transport, and contract errors.
# wallets.getPasskeyOwner
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/accounts/get-passkey-owner
Read the public passkey owner descriptor.
`namera.wallets.getPasskeyOwner()` read the public passkey owner descriptor.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.getPasskeyOwner("0199dfe1-0000-7000-8000-000000000004");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns `walletId` and `owner`. Managed accounts return `owner: null`. A passkey descriptor includes signing-key ID, uncompressed public key, credential ID, RP ID, and origin; it contains no signing capability.
```json
{
"walletId": "0199dfe1-0000-7000-8000-000000000004",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000016",
"publicKeyHex": "0x0411111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
"credentialId": "dGVzdA",
"rpId": "app.example.com",
"origin": "https://app.example.com"
}
}
```
## Parameters [#parameters]
### walletId [#walletid]
Type: `string`. Required. Account UUID, not its address. Obtain it from account creation or listing.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.getPasskeyOwner("0199dfe1-0000-7000-8000-000000000004"); // [!code focus]
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Behavior and errors [#behavior-and-errors]
Requires `wallet:read` for workspace-wide API-key access. `WALLET_NOT_FOUND` means the account is missing or outside the workspace. Use the descriptor together with independently reviewed account and installation configuration when validating a passkey approval.
# List Accounts
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/accounts/list-accounts
Read the accounts available to your credential.
`namera.wallets.list()` returns accounts reachable through active session grants,
or all workspace accounts when the API key has explicit `wallet:read` permission.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.wallets.list();
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
An array of complete records. An empty array means no matching resources are available. The method is not paginated.
- **`id`** (`string`): Account ID.
- **`organizationId`** (`string`): Owning organization ID.
- **`metadata`** (`object`): version and name, with optional logo and description.
- **`status`** (`"active" | "frozen" | "archived"`): Account lifecycle status.
- **`namespace`** (`"eip155"`): Chain namespace.
- **`address`** (`` `0x${string}` ``): Smart-account address.
- **`owner`** (`object`): Public signing-key identity, custody, algorithm, and provider-specific protection details.
- **`implementation`** (`"alchemy-modular-v2"`): Smart-account implementation.
- **`data`** (`object`): Account configuration, discriminated by validatorType and accountMode. Includes deployment and version fields.
- **`createdAt`** (`DateTime.Utc`): Creation time.
- **`updatedAt`** (`DateTime.Utc`): Last update time.
### Example Response [#example-response]
```json
[
{
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"metadata": {
"version": 1,
"name": "Example account",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "SDK test account"
},
"status": "active",
"namespace": "eip155",
"address": "0x1111111111111111111111111111111111111111",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000005",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "7702",
"delegationVersion": "v1.1.0"
},
"createdAt": "2026-10-11T09:00:00.000Z",
"updatedAt": "2026-10-11T09:00:00.000Z"
}
]
```
## Parameters [#parameters]
None. `wallets.list()` does not accept filters or pagination options.
## Errors [#errors]
API failures return `success: false`. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors)
for authentication, transport, and contract errors.
# Get Current Actor
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/authentication/get-current-actor
Inspect the identity, organization, and grants behind your credential.
`namera.auth.currentActor()` returns the actor authenticated by the client's
credential. Use it to check which organization, management permissions, and session-key grants your
integration is using.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.auth.currentActor();
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
The successful data is a discriminated union with `type` and `data` fields.
Check `type` before reading credential-specific fields.
- **`type`** (`"api-key" | "cli" | "mcp" | "user"`): Authenticated actor kind.
API keys return `"api-key"`; OAuth authorizations return `"cli"` or `"mcp"`
according to the authorizing client. The shared API contract also includes
`"user"` for authenticated user sessions.
- **`data.actorId`** (`string`): Durable actor identity, distinct from the API
key or OAuth authorization ID.
### API Key and OAuth Actors [#api-key-and-oauth-actors]
These actor kinds share the following fields:
- **`data.organizationId`** (`string`): Organization the credential belongs to.
- **`data.organizationName`** (`string | undefined`): Organization display name,
when available. Use the ID rather than the name to identify the organization.
- **`data.grants`** (`array`): Session-key grants available to the actor. Each entry
contains a `grant` record and its `sessionKey` record. An empty array means
there are no delegated execution/signing grants to use. API-key management
permissions can independently authorize workspace management.
- **`data.grants[].grant`** (`object`): Grant ID, organization ID, actor ID,
session-key ID, granting actor ID, creation time, and nullable revocation time
and revoking actor ID.
- **`data.grants[].sessionKey`** (`object`): Session-key ID, organization and
account IDs, signing-key ID, creating actor ID, metadata, namespace, policies,
policy hash, lifecycle status, creation time, and nullable revocation fields.
This is the session record, not the expanded installation and signer view
returned by [Get Session Key](https://namera.ai/docs/sdk/reference/session-keys/get-session-key).
For `"api-key"`, **`data.apiKey`** contains `id`, `metadata`, `keyStart`,
`permissions`, `passkeyOrigins`, `expiresAt`, `lastUsedAt`, and `createdAt`.
`permissions` lists explicitly issued workspace management capabilities;
`passkeyOrigins` lists approved application origins. `keyStart` is a display prefix, not
the secret key. Expiry and last-use times can be `null`.
For `"cli"` and `"mcp"`, **`data.authorization`** contains `id`, `clientId`,
`scopes`, `metadata`, `expiresAt`, `lastUsedAt`, and `createdAt`. OAuth scopes
and session-key grants are separate restrictions; a grant does not bypass scopes.
For `"user"`, **`data`** contains `actorId`, `session`, `user`, `organization`,
`member`, and `role` instead of delegated grants and credential metadata.
### Example Response [#example-response]
An API-key actor with one session-key grant:
```json
{
"type": "api-key",
"data": {
"actorId": "0199dfe1-0000-7000-8000-000000000014",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"organizationName": "Example workspace",
"grants": [
{
"grant": {
"id": "0199dfe1-0000-7000-8000-000000000013",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"actorId": "0199dfe1-0000-7000-8000-000000000014",
"sessionKeyId": "0199dfe1-0000-7000-8000-000000000002",
"grantedByActorId": "0199dfe1-0000-7000-8000-000000000015",
"revokedAt": null,
"revokedByActorId": null,
"createdAt": "2026-10-11T09:00:00.000Z"
},
"sessionKey": {
"id": "0199dfe1-0000-7000-8000-000000000002",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"signingKeyId": "0199dfe1-0000-7000-8000-000000000005",
"createdByActorId": "0199dfe1-0000-7000-8000-000000000015",
"metadata": {
"version": 1,
"name": "Example session",
"logo": { "type": "emoji", "value": "π" },
"description": "SDK test session"
},
"policyHash": "0x3333333333333333333333333333333333333333333333333333333333333333",
"status": "active",
"revokedAt": null,
"revokedByActorId": null,
"createdAt": "2026-10-11T09:00:00.000Z",
"namespace": "eip155",
"policies": [
{
"id": "0199dfe1-0000-7000-8000-000000000016",
"appliesTo": "signature",
"type": "evm.chain-allowlist",
"version": 1,
"chainIds": ["eip155:84532"]
}
]
}
}
],
"apiKey": {
"permissions": [],
"passkeyOrigins": [],
"id": "0199dfe1-0000-7000-8000-000000000017",
"metadata": {
"version": 1,
"name": "Example integration",
"logo": { "type": "emoji", "value": "π" },
"description": "SDK test credential"
},
"keyStart": "example-prefix",
"expiresAt": null,
"lastUsedAt": "2026-10-11T09:10:00.000Z",
"createdAt": "2026-10-11T09:00:00.000Z"
}
}
}
```
## Parameters [#parameters]
None. Authentication comes from the [client configuration](https://namera.ai/docs/sdk/reference/client/namera-client).
The method cannot look up a different actor by ID.
## Check the Actor Type [#check-the-actor-type]
Narrow the response before accessing grants. A grant describes delegated access;
execution still requires an active session installed on the selected network
and policies that allow the operation.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.auth.currentActor();
if (!result.success) throw new Error(result.error.message);
const actor = result.data;
if (actor.type === "api-key") {
console.log(actor.data.grants);
}
```
## Errors [#errors]
Invalid, expired, or revoked credentials return `success: false`. This read does
not create grants or refresh an OAuth token. If you use `getAccessToken`, your
callback supplies the token for the request.
The SDK does not automatically retry this method. See
[Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for error
inspection and [Authentication](https://namera.ai/docs/sdk/authentication) for credential setup.
# NameraClient
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/client/namera-client
Create and configure the Namera SDK client.
`new NameraClient(config)` creates a client. Construction does not authenticate or send an API request.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const accounts = await namera.wallets.list();
if (!accounts.success) throw new Error(accounts.error.message);
console.log(accounts.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
A `NameraClient` instance. Creating it does not make a network request.
- **`wallets`** (`WalletClient`): list() and get(walletId).
- **`sessionKeys`** (`SessionKeyClient`): list(options?) and get(sessionKeyId).
- **`executions`** (`ExecutionClient`): execute, simulate, getStatus, list, and get. Also exposes low-level prepare and complete.
- **`sign`** (`(request: SignRequest) => Promise`): Sign a message or typed data.
- **`verifySignature`** (`(request: VerifySignatureRequest) => Promise`): Verify a smart-account signature.
- **`signatures`** (`SignatureClient`): Advanced prepare and complete transport, plus sign.
- **`auth`** (`AuthClient`): Read the authenticated actor with currentActor().
## Parameters [#parameters]
Pass a `NameraClientConfig` object. Exactly one of `apiKey`, `accessToken`, or `getAccessToken` is required.
### apiKey [#apikey]
- **Type:** `string`
- **Optional**
Authenticates server-side requests using the `x-api-key` header. Keep API keys out of browser bundles and source control. Do not combine this with an OAuth option.
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!, // [!code focus]
});
```
### accessToken [#accesstoken]
- **Type:** `string`
- **Optional**
The OAuth token used for requests. Pass only the token; the SDK adds the `Bearer` prefix. Use `getAccessToken` if your application needs to supply refreshed tokens.
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
accessToken: process.env.NAMERA_ACCESS_TOKEN!, // [!code focus]
});
```
### getAccessToken [#getaccesstoken]
- **Type:** `() => Promise`
- **Optional**
An asynchronous token supplier invoked when requests need authentication. It must resolve to a token string. Your application owns refresh and storage.
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
getAccessToken: async () => process.env.NAMERA_ACCESS_TOKEN!, // [!code focus]
});
```
Replace this environment lookup with your applicationβs token store or refresh flow.
### baseUrl [#baseurl]
- **Type:** `string`
- **Optional**
- **Default:** `https://api.namera.ai`
The API deployment to connect to. Omit for Nameraβs hosted API. Use another URL only for an alternative deployment; do not include endpoint paths or credentials.
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
baseUrl: "http://localhost:8080", // [!code focus]
});
```
### fetch [#fetch]
- **Type:** `NameraFetch`
- **Optional**
- **Default:** `platform fetch`
Overrides the Fetch implementation used for HTTP requests. Preserve the supplied request and authentication headers when wrapping it.
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
fetch: (input, init) => globalThis.fetch(input, init), // [!code focus]
});
```
### maxGasCostWei [#maxgascostwei]
- **Type:** `bigint`
- **Optional**
Maximum approved gas cost in wei for a self-funded operation. Set before executing with `sponsor: false`. This is a ceiling, not a gas price or an extra payment; preparations above it are rejected.
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
import { parseEther } from "viem";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
maxGasCostWei: parseEther("0.0001"), // [!code focus]
});
```
Install `viem` for `parseEther`. Applies to managed and automatically resolved local executions. Custom signers use their own fee ceiling.
### localSigning [#localsigning]
- **Type:** `false`
- **Optional**
Set to `false` to prevent automatic Node.js key-store access. Omitting this option enables resolution for imported local keys. It does not disable an explicit `resolveSessionSigner`.
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
localSigning: false, // [!code focus]
});
```
### resolveSessionSigner [#resolvesessionsigner]
- **Type:** `ResolveSessionSigner`
- **Optional**
Overrides resolution for applications with their own key store. Returns a `LocalSessionSigner` with a trusted `binding`, `signMessage`, optional `signTypedData`, and optional `maxGasCostWei`.
Use owner-reviewed configuration for the binding, never the preparation response. Signature operations require a typed-data callback and approved signature authority. Standard Node.js integrations using imported keys can omit this option.
## Result Handling [#result-handling]
API methods return `NameraResult`. Check `success` before reading `data`. On success `error` is null; on failure `data` is null. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors).
## Advanced Signing [#advanced-signing]
Node.js resolves imported local session keys automatically. An explicit resolver takes precedence. Browser bundles do not include native key storage.
Prefer `execute()` and `sign()` over low-level prepare and complete methods, whose callers must independently validate what they sign.
# Execute
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/executions/execute
Prepare, authorize, and submit one or more EVM calls.
`namera.executions.execute(request)` validates and signs the prepared operation, then queues it for broadcast. Each invocation starts a new submission.
## Usage [#usage]
Install `@namera-ai/sdk` and `viem`. Replace the example IDs and recipient with your own. The selected session must permit these calls on Base Sepolia.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
- **`namespace`** (`"eip155"`): Chain namespace.
- **`submissionId`** (`string`): ID to pass to executions.getStatus().
- **`status`** (`"prepared" | "submitted" | "confirmed" | "failed"`): Current submission state. Prepared is queued, not confirmed.
- **`userOperationHash`** (`` `0x${string}` ``): ERC-4337 user-operation hash, not a transaction hash.
### Example Response [#example-response]
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "prepared",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
## Parameters [#parameters]
Pass an `ExecuteRequest` object. Fields below are required unless marked optional.
### namespace [#namespace]
- **Type:** `"eip155"`
- **Required**
The blockchain namespace. Use `"eip155"` for every currently supported Namera
network. This is not a chain ID; select the specific network with `chainId`.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155", // [!code focus]
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
### walletId [#walletid]
- **Type:** `string`
- **Required**
The account UUID returned by `wallets.list()` or `wallets.get()`. Pass its `id`,
not its onchain `address`. The account must be accessible to the clientβs credential.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001", // [!code focus]
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
### sessionKeyId [#sessionkeyid]
- **Type:** `string`
- **Required**
The session-key UUID returned by `sessionKeys.list()` or `sessionKeys.get()`.
This identifies the delegated session, not its signing key or network installation.
Execution and signing require an active grant for this key. Management reads may
instead use explicit workspace `session-key:read` permission.
For execution or signing, choose a key belonging to `walletId` with a confirmed
installation on `chainId` and permissions that allow the requested operation.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002", // [!code focus]
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
### chainId [#chainid]
- **Type:** `SupportedEvmChainId`
- **Required**
The target network in CAIP-2 format. For Base Sepolia, use `"eip155:84532"`,
not `84532` or `"84532"`. Use the network on which the account will execute, sign, or verify the payload.
The SDK restricts this field to the [supported network IDs](https://namera.ai/docs/sdk/supported-networks).
Network availability is also checked by the API.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532", // [!code focus]
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
### calls [#calls]
- **Type:** `readonly { to: EthereumAddress; value: bigint; data: Hex }[]`
- **Required**
One or more EVM calls, in execution order. Every call uses the same account,
network, and session key. Supply all three fields on each call; there are no
implicit values for `value` or `data`.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"), // [!code focus]
data: "0x",
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
#### calls.to [#callsto]
- **Type:** `EthereumAddress` (`` `0x${string}` ``)
- **Required**
The 20-byte recipient or contract address. Native transfers target the recipient;
contract calls target the contract, not the recipient encoded in its arguments.
The sessionβs permissions must allow this target.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222", // [!code focus]
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
#### calls.value [#callsvalue]
- **Type:** `bigint`
- **Required**
The native-token amount in wei. Use `parseEther("0.001")` for 0.001 ETH or `0n`
for a call that sends no native tokens. Negative amounts are rejected. ERC-20
amounts belong in encoded calldata, not this field.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"), // [!code focus]
data: "0x",
},
],
sponsor: true,
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
#### calls.data [#callsdata]
- **Type:** `Hex` (`` `0x${string}` ``)
- **Required**
The encoded contract call. Use `"0x"` for a native transfer. For contract functions,
use viemβs `encodeFunctionData`; the SDK does not accept `abi`, `functionName`, or
`args` directly in a call.
```ts title="index.ts"
import { namera } from "./client";
import { encodeFunctionData, erc20Abi, parseUnits } from "viem";
const result = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x3333333333333333333333333333333333333333",
value: 0n,
data: encodeFunctionData({
// [!code focus:5]
abi: erc20Abi,
functionName: "transfer",
args: ["0x2222222222222222222222222222222222222222", parseUnits("1", 6)],
}),
},
],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
This encodes a transfer of one token with six decimals. Use your tokenβs actual
decimals and pass its contract address as `to`.
### sponsor [#sponsor]
- **Type:** `boolean`
- **Optional**
- **Default:** `true`
Sponsorship covers gas, not transferred assets, and remains subject to workspace allowances and policies.
Set `false` to pay from the account. Fund both the transfer and gas, and configure [maxGasCostWei](https://namera.ai/docs/sdk/reference/client/namera-client#maxgascostwei). A custom signer must carry its own fee ceiling.
See [Sponsor Gas](https://namera.ai/docs/sdk/guides/transactions/sponsor-gas) for a complete self-funded example.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.execute({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
sponsor: true, // [!code focus]
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
## Behavior [#behavior]
Use [Get Submission Status](https://namera.ai/docs/sdk/reference/executions/get-submission-status) to track this submission. Do not call execute again to poll. Internal preparation retries reuse one idempotency key; completion retries reuse the same submission.
## Errors [#errors]
Policy, authorization, billing, and execution failures return `success: false`. Prepared-operation validation failures use `kind: "signer"`. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors)
for authentication, transport, and contract errors.
Guide: [Transfer Assets](https://namera.ai/docs/sdk/guides/transactions/transfer-assets).
# Get Execution
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/executions/get-execution
Read a confirmed execution, receipt, and related resources.
`namera.executions.get(executionId)` returns the full confirmed record.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.executions.get("0199dfe1-0000-7000-8000-000000000012");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
- **`execution`** (`ExecutionResponse`): id, executionSubmissionId, organizationId, sessionKeyGrantId, namespace, data, and createdAt.
- **`execution.data`** (`EvmExecutionData`): version, namespace, chainId, calls, userOperationHash, transactionHash, and receipt.
- **`execution.data.receipt`** (`SuccessfulEvmExecutionReceipt`): Successful user-operation receipt including block, gas, sender, and EntryPoint.
- **`wallet`** (`WalletResponse`): Complete account record.
- **`sessionKey`** (`SessionKeySummaryResponse`): Session identity, metadata, policies, lifecycle, and creation fields without expanded relations.
- **`actor`** (`ExecutionActorDetailsResponse`): Discriminated by type. user has member; api-key has apiKey; cli and mcp have authorization. Includes id and public credential details, never raw secrets.
### Example Response [#example-response]
```json
{
"execution": {
"id": "0199dfe1-0000-7000-8000-000000000012",
"executionSubmissionId": "0199dfe1-0000-7000-8000-000000000003",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"sessionKeyGrantId": "0199dfe1-0000-7000-8000-000000000013",
"namespace": "eip155",
"data": {
"version": 1,
"chainId": "eip155:84532",
"calls": [
{
"to": "0x2222222222222222222222222222222222222222",
"value": "1000000000000000",
"data": "0x"
}
],
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"transactionHash": "0x5555555555555555555555555555555555555555555555555555555555555555",
"receipt": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:84532",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"transactionHash": "0x5555555555555555555555555555555555555555555555555555555555555555",
"blockHash": "0x6666666666666666666666666666666666666666666666666666666666666666",
"blockNumber": "32000000",
"sender": "0x1111111111111111111111111111111111111111",
"nonce": "0",
"entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"paymaster": null,
"actualGasCost": "0",
"actualGasUsed": "120000",
"success": true,
"reason": null
}
},
"createdAt": "2026-10-11T09:10:00.000Z"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"metadata": {
"version": 1,
"name": "Example account",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "SDK test account"
},
"status": "active",
"namespace": "eip155",
"address": "0x1111111111111111111111111111111111111111",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000005",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "7702",
"delegationVersion": "v1.1.0"
},
"createdAt": "2026-10-11T09:00:00.000Z",
"updatedAt": "2026-10-11T09:00:00.000Z"
},
"sessionKey": {
"id": "0199dfe1-0000-7000-8000-000000000002",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"signingKeyId": "0199dfe1-0000-7000-8000-000000000006",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Example session",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "Send 0.001 test ETH on Base Sepolia"
},
"policies": [],
"policyHash": "1111111111111111111111111111111111111111111111111111111111111111",
"status": "active",
"revokedAt": null,
"createdAt": "2026-10-11T09:05:00.000Z"
},
"actor": {
"id": "0199dfe1-0000-7000-8000-000000000012",
"type": "api-key",
"apiKey": {
"id": "0199dfe1-0000-7000-8000-000000000013",
"metadata": {
"version": 1,
"name": "Example integration",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "SDK examples"
},
"keyStart": "example",
"expiresAt": null,
"lastUsedAt": "2026-10-11T09:10:00.000Z",
"revokedAt": null,
"createdAt": "2026-10-11T09:00:00.000Z",
"updatedAt": "2026-10-11T09:00:00.000Z"
}
}
}
```
## Parameters [#parameters]
### executionId [#executionid]
- **Type:** `string`
- **Required**
The confirmed executionβs `id`, returned by `executions.list()` or inside the confirmed `getStatus()` execution record. Submission IDs and transaction hashes are different identifiers and cannot be used here.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.executions.get("0199dfe1-0000-7000-8000-000000000012"); // [!code focus]
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Errors [#errors]
`EXECUTION_NOT_FOUND` means the confirmed record is missing or unavailable to your credential. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for shared authentication, transport, and contract errors.
# Get Submission Status
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/executions/get-submission-status
Read the current state of an execution submission.
`namera.executions.getStatus(submissionId)` tracks a submission before and after confirmation.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.executions.getStatus("0199dfe1-0000-7000-8000-000000000003");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
- **`namespace`** (`"eip155"`): Chain namespace.
- **`submissionId`** (`string`): Requested submission UUID.
- **`status`** (`"reserved" | "prepared" | "submitted" | "confirmed" | "failed"`): Discriminator for the response shape.
- **`userOperationHash`** (`` `0x${string}` | null ``): Present only for reserved, prepared, and submitted.
- **`execution`** (`ExecutionResponse`): Complete confirmed execution record. Present only for confirmed.
### Pending Response [#pending-response]
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "submitted",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
```
### Confirmed Response [#confirmed-response]
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "confirmed",
"execution": {
"id": "0199dfe1-0000-7000-8000-000000000012",
"executionSubmissionId": "0199dfe1-0000-7000-8000-000000000003",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"sessionKeyGrantId": "0199dfe1-0000-7000-8000-000000000013",
"namespace": "eip155",
"data": {
"version": 1,
"chainId": "eip155:84532",
"calls": [
{
"to": "0x2222222222222222222222222222222222222222",
"value": "1000000000000000",
"data": "0x"
}
],
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"transactionHash": "0x5555555555555555555555555555555555555555555555555555555555555555",
"receipt": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:84532",
"userOperationHash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"transactionHash": "0x5555555555555555555555555555555555555555555555555555555555555555",
"blockHash": "0x6666666666666666666666666666666666666666666666666666666666666666",
"blockNumber": "32000000",
"sender": "0x1111111111111111111111111111111111111111",
"nonce": "0",
"entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"paymaster": null,
"actualGasCost": "0",
"actualGasUsed": "120000",
"success": true,
"reason": null
}
},
"createdAt": "2026-10-11T09:10:00.000Z"
}
}
```
### Failed Response [#failed-response]
```json
{
"namespace": "eip155",
"submissionId": "0199dfe1-0000-7000-8000-000000000003",
"status": "failed"
}
```
## Parameters [#parameters]
### submissionId [#submissionid]
- **Type:** `string`
- **Required**
The `submissionId` returned by `execute()`. Save it to resume tracking after a restart. It is neither the confirmed execution ID nor an onchain transaction hash.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.executions.getStatus("0199dfe1-0000-7000-8000-000000000003"); // [!code focus]
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Polling [#polling]
Check the same submission while its status is `reserved`, `prepared`, or `submitted`. Stop on `confirmed` or `failed`. This method performs one read; it does not poll automatically. Do not call `execute()` again to check progress.
## Errors [#errors]
`EXECUTION_SUBMISSION_NOT_FOUND` means the submission is missing or unavailable to your credential. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for shared authentication, transport, and contract errors.
Guide: [Track Transactions](https://namera.ai/docs/sdk/guides/transactions/track-transactions).
# List Executions
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/executions/list-executions
List confirmed executions with cursor pagination.
`namera.executions.list(options?)` returns confirmed history. Pending submissions are not included.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.executions.list({
walletId: "0199dfe1-0000-7000-8000-000000000001",
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
- **`items`** (`readonly ExecutionListItemResponse[]`): Confirmed records accessible to your credential.
- **`items[].details`** (`object`): id, namespace, chainId, transactionHash, and createdAt.
- **`items[].wallet`** (`object`): id, namespace, address, and metadata.
- **`items[].sessionKey`** (`object`): id, namespace, and metadata.
- **`items[].actorType`** (`"user" | "api-key" | "mcp" | "cli"`): Submitting actor kind.
- **`nextCursor`** (`string | null`): Pass as cursor for the next page; null ends pagination.
### Example Response [#example-response]
```json
{
"items": [
{
"details": {
"id": "0199dfe1-0000-7000-8000-000000000012",
"namespace": "eip155",
"chainId": "eip155:84532",
"transactionHash": "0x5555555555555555555555555555555555555555555555555555555555555555",
"createdAt": "2026-10-11T09:10:00.000Z"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000000001",
"namespace": "eip155",
"address": "0x1111111111111111111111111111111111111111",
"metadata": {
"version": 1,
"name": "Example account",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "SDK test account"
}
},
"sessionKey": {
"id": "0199dfe1-0000-7000-8000-000000000002",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Example session",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "Send test ETH on Base Sepolia"
}
},
"actorType": "api-key"
}
],
"nextCursor": null
}
```
## Parameters [#parameters]
The optional `options` object defaults to `{}`.
### walletId [#walletid]
- **Type:** `string`
- **Optional**
Restricts results to the account UUID, not its address. Combine with `sessionKeyId` to narrow the results further.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.executions.list({
walletId: "0199dfe1-0000-7000-8000-000000000001", // [!code focus]
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### sessionKeyId [#sessionkeyid]
- **Type:** `string`
- **Optional**
Restricts results to confirmed executions authorized by this session. Pending submissions are excluded.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.executions.list({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002", // [!code focus]
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### cursor [#cursor]
- **Type:** `string`
- **Optional**
Use `nextCursor` from the previous page. Omit for the first page and stop when it is `null`. Preserve the same filters across pages. There is no configurable page-size parameter.
```ts title="index.ts"
import { namera } from "./client";
const first = await namera.executions.list();
if (!first.success) throw new Error(first.error.message);
if (first.data.nextCursor !== null) {
const next = await namera.executions.list({
cursor: first.data.nextCursor, // [!code focus]
});
if (!next.success) throw new Error(next.error.message);
console.log(next.data);
}
```
## Errors [#errors]
Invalid filter IDs return a contract error. API failures return `success: false`. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for shared authentication, transport, and contract errors.
Guide: [Track Transactions](https://namera.ai/docs/sdk/guides/transactions/track-transactions).
# Simulate
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/executions/simulate
Simulate calls and check the selected sessionβs installed authority.
`namera.executions.simulate(request)` does not sign, submit, or sponsor an operation.
## Usage [#usage]
Install `@namera-ai/sdk` and `viem`. Replace the example IDs and recipient with your own. The selected session must permit these calls on Base Sepolia.
```ts title="index.ts"
import { namera } from "./client";
import type { SimulateExecutionRequest } from "@namera-ai/sdk";
import { parseEther } from "viem";
const request = {
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
} satisfies SimulateExecutionRequest;
const simulation = await namera.executions.simulate(request);
if (!simulation.success) throw new Error(simulation.error.message);
console.log(simulation.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
- **`namespace`** (`"eip155"`): Chain namespace.
- **`walletId`** (`string`): Account UUID.
- **`chainId`** (`SupportedEvmChainId`): Simulation network.
- **`account`** (`` `0x${string}` ``): Smart-account address.
- **`callsSucceeded`** (`boolean`): Whether the simulated calls succeeded.
- **`simulation`** (`EvmIntentSimulation`): userOperation gas estimates and calls results, assetChanges, and transfers.
- **`allowed`** (`boolean`): Point-in-time eligibility; not a guarantee of later execution.
- **`sessionKeyId`** (`string`): Present when allowed is true.
- **`denials`** (`readonly { sessionKeyId: string; policyId: string; code: EvmPolicyDenialCode }[]`): Legacy response variant retained for client compatibility; current servers return errors for failed authorization or simulation, not policy denials.
### Example Response [#example-response]
```json
{
"namespace": "eip155",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"chainId": "eip155:84532",
"account": "0x1111111111111111111111111111111111111111",
"callsSucceeded": true,
"simulation": {
"userOperation": {
"source": "eth_estimateUserOperationGas",
"callGasLimit": "50000",
"verificationGasLimit": "100000",
"preVerificationGas": "50000",
"maxFeePerGas": "1000000000",
"maxPriorityFeePerGas": "1000000"
},
"calls": {
"source": "viem.simulateCalls",
"results": [
{
"status": "success",
"returnData": "0x",
"gasUsed": "21000"
}
],
"assetChanges": [],
"transfers": [
{
"callIndex": 0,
"from": "0x1111111111111111111111111111111111111111",
"to": "0x2222222222222222222222222222222222222222",
"value": "1000000000000000"
}
]
}
},
"allowed": true,
"sessionKeyId": "0199dfe1-0000-7000-8000-000000000002"
}
```
## Parameters [#parameters]
Pass a `SimulateExecutionRequest` object. Simulation does not accept a `sponsor` field.
### namespace [#namespace]
- **Type:** `"eip155"`
- **Required**
The blockchain namespace. Use `"eip155"` for every currently supported Namera
network. This is not a chain ID; select the specific network with `chainId`.
```ts title="index.ts"
import { namera } from "./client";
import type { SimulateExecutionRequest } from "@namera-ai/sdk";
import { parseEther } from "viem";
const request = {
namespace: "eip155", // [!code focus]
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
} satisfies SimulateExecutionRequest;
const simulation = await namera.executions.simulate(request);
if (!simulation.success) throw new Error(simulation.error.message);
console.log(simulation.data);
```
### walletId [#walletid]
- **Type:** `string`
- **Required**
The account UUID returned by `wallets.list()` or `wallets.get()`. Pass its `id`,
not its onchain `address`. The account must be accessible to the clientβs credential.
```ts title="index.ts"
import { namera } from "./client";
import type { SimulateExecutionRequest } from "@namera-ai/sdk";
import { parseEther } from "viem";
const request = {
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001", // [!code focus]
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
} satisfies SimulateExecutionRequest;
const simulation = await namera.executions.simulate(request);
if (!simulation.success) throw new Error(simulation.error.message);
console.log(simulation.data);
```
### sessionKeyId [#sessionkeyid]
- **Type:** `string`
- **Required**
The session-key UUID returned by `sessionKeys.list()` or `sessionKeys.get()`.
This identifies the delegated session, not its signing key or network installation.
Execution and signing require an active grant for this key. Management reads may
instead use explicit workspace `session-key:read` permission.
For execution or signing, choose a key belonging to `walletId` with a confirmed
installation on `chainId` and permissions that allow the requested operation.
```ts title="index.ts"
import { namera } from "./client";
import type { SimulateExecutionRequest } from "@namera-ai/sdk";
import { parseEther } from "viem";
const request = {
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002", // [!code focus]
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
} satisfies SimulateExecutionRequest;
const simulation = await namera.executions.simulate(request);
if (!simulation.success) throw new Error(simulation.error.message);
console.log(simulation.data);
```
### chainId [#chainid]
- **Type:** `SupportedEvmChainId`
- **Required**
The target network in CAIP-2 format. For Base Sepolia, use `"eip155:84532"`,
not `84532` or `"84532"`. Use the network on which the account will execute, sign, or verify the payload.
The SDK restricts this field to the [supported network IDs](https://namera.ai/docs/sdk/supported-networks).
Network availability is also checked by the API.
```ts title="index.ts"
import { namera } from "./client";
import type { SimulateExecutionRequest } from "@namera-ai/sdk";
import { parseEther } from "viem";
const request = {
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532", // [!code focus]
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"),
data: "0x",
},
],
} satisfies SimulateExecutionRequest;
const simulation = await namera.executions.simulate(request);
if (!simulation.success) throw new Error(simulation.error.message);
console.log(simulation.data);
```
### calls [#calls]
- **Type:** `readonly { to: EthereumAddress; value: bigint; data: Hex }[]`
- **Required**
One or more EVM calls, in execution order. Every call uses the same account,
network, and session key. Supply all three fields on each call; there are no
implicit values for `value` or `data`.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.simulate({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"), // [!code focus]
data: "0x",
},
],
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
#### calls.to [#callsto]
- **Type:** `EthereumAddress` (`` `0x${string}` ``)
- **Required**
The 20-byte recipient or contract address. Native transfers target the recipient;
contract calls target the contract, not the recipient encoded in its arguments.
The sessionβs permissions must allow this target.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.simulate({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222", // [!code focus]
value: parseEther("0.001"),
data: "0x",
},
],
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
#### calls.value [#callsvalue]
- **Type:** `bigint`
- **Required**
The native-token amount in wei. Use `parseEther("0.001")` for 0.001 ETH or `0n`
for a call that sends no native tokens. Negative amounts are rejected. ERC-20
amounts belong in encoded calldata, not this field.
```ts title="index.ts"
import { namera } from "./client";
import { parseEther } from "viem";
const execution = await namera.executions.simulate({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x2222222222222222222222222222222222222222",
value: parseEther("0.001"), // [!code focus]
data: "0x",
},
],
});
if (!execution.success) throw new Error(execution.error.message);
console.log(execution.data);
```
#### calls.data [#callsdata]
- **Type:** `Hex` (`` `0x${string}` ``)
- **Required**
The encoded contract call. Use `"0x"` for a native transfer. For contract functions,
use viemβs `encodeFunctionData`; the SDK does not accept `abi`, `functionName`, or
`args` directly in a call.
```ts title="index.ts"
import { namera } from "./client";
import { encodeFunctionData, erc20Abi, parseUnits } from "viem";
const result = await namera.executions.simulate({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
calls: [
{
to: "0x3333333333333333333333333333333333333333",
value: 0n,
data: encodeFunctionData({
// [!code focus:5]
abi: erc20Abi,
functionName: "transfer",
args: ["0x2222222222222222222222222222222222222222", parseUnits("1", 6)],
}),
},
],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
This encodes a transfer of one token with six decimals. Use your tokenβs actual
decimals and pass its contract address as `to`.
## Errors [#errors]
Execution, authorization, and network failures return `success: false`. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors)
for authentication, transport, and contract errors.
Guide: [Simulate Transactions](https://namera.ai/docs/sdk/guides/transactions/simulate-transactions).
# sessionKeys.approveOperation
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/session-keys/approve-operation
Approve a prepared installation or removal.
`namera.sessionKeys.approveOperation()` approve a prepared installation or removal.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.approveOperation({
operationId: "0199dfe1-0000-7000-8000-000000000014",
approval: { type: "1claw" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns the operation ID and durable status. `signed` means the signed request was persisted for worker submission; it does not mean the installation is confirmed.
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000000014",
"status": "signed"
}
```
## Parameters [#parameters]
### operationId [#operationid]
Type: `string`. Required. ID returned by preparation or recovery. It must belong to this same API-key actor.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.approveOperation({
operationId: "0199dfe1-0000-7000-8000-000000000014", // [!code focus]
approval: { type: "1claw" },
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### approval [#approval]
Type: `object`. Required. Use `{ type: "1claw" }` for a managed account owner. This explicitly authorizes managed owner signing. For a passkey owner use `{ type: "passkey", response }`, where `response` is the browserβs complete assertion over the validated preparation challenge.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.approveOperation({
operationId: "0199dfe1-0000-7000-8000-000000000014",
approval: { type: "1claw" }, // [!code focus]
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
#### approval.response [#approvalresponse]
Type: `PasskeyAuthenticationResponse`. Required only for `type: "passkey"`. The assertion must match the stored account credential, challenge, RP ID, origin, and counter. Keep API credentials on your backend; the browser returns only its assertion to your application.
## Behavior and errors [#behavior-and-errors]
Requires the matching install/uninstall permission. Authorization is checked again before managed signing and at acceptance; revocation prevents unaccepted work from gaining authority. Only the initiating actor can approve. Transient retries reuse the same operation and exact assertion. Accepted signed work remains subject to reconciliation after API-key revocation. Validate using `validateOwnerApproval()` or `validateManagedOwnerApproval()` before this call; the SDK does not silently approve prepared calldata for you. Those helpers require independently reconstructed owner, deployment, call, and fee expectations, not values copied from the preparation.
# sessionKeys.cancelOperation
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/session-keys/cancel-operation
Cancel an unsigned installation or removal preparation.
`namera.sessionKeys.cancelOperation()` cancel an unsigned installation or removal preparation.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.cancelOperation("0199dfe1-0000-7000-8000-000000000014");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns `operationId` and `status: "cancelled"`.
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000000014",
"status": "cancelled"
}
```
## Parameters [#parameters]
### operationId [#operationid]
Type: `string`. Required. Resource UUID returned by creation, preparation, or recovery; not an address or transaction hash.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.cancelOperation("0199dfe1-0000-7000-8000-000000000014"); // [!code focus]
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Behavior and errors [#behavior-and-errors]
Requires the operationβs install/uninstall permission and the initiating actor. Signed or submitted work cannot be cancelled; it must reconcile. Cancellation changes no session grants or onchain permissions.
# sessionKeys.create
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/session-keys/create-session-key
Register a local or 1Claw-managed session signer.
`namera.sessionKeys.create()` register a local or 1Claw-managed session signer.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.create({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
metadata: { version: 1, name: "Local agent" },
signer: { custody: "namera-managed", provider: "1claw", algorithm: "secp256k1" },
onchain: {
installations: [
{
chainId: "eip155:11155111",
validAfter: Math.floor(Date.now() / 1000),
validUntil: Math.floor(Date.now() / 1000) + 3600,
permissions: [{ type: "root" }],
allowSignatures: false,
},
],
},
policies: [],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns the complete pending session, public signer, account, creator, and per-network installations. API-key creators use `{ type: "api-key", actorId, id, metadata }`; human creators retain the member/user/role shape. This fixture uses root authority; choose narrower permissions for restricted agents.
```json
{
"id": "0199dfe1-0000-7000-8000-000000000003",
"organizationId": "0199dfe1-0000-7000-8000-000000000006",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"signingKeyId": "0199dfe1-0000-7000-8000-000000000012",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Local agent"
},
"policies": [],
"policyHash": "9Z4ZzPfiQ4hIUpSXTY_nQ2E9-kjd2w_5wbLwIj7visI",
"status": "pending",
"revokedAt": null,
"createdAt": "2026-10-15T02:39:05.307Z",
"signer": {
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1",
"publicKey": "0x04e37a5065266fa599595e06a6968cdfe2d588cfbbbbb48f0d4c504048c53786a87ff061f472d579833ea98e99f425febabd2445a8760e225cb1e5b4a029cd18b8"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000006",
"metadata": {
"version": 1,
"name": "Provisioned account"
},
"status": "active",
"namespace": "eip155",
"address": "0x3333333333333333333333333333333333333333",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000008",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"createdAt": "2026-10-15T02:39:05.250Z",
"updatedAt": "2026-10-15T02:39:05.250Z",
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "factory",
"factoryVersion": "2.0.0",
"implementationVersion": "v1.0.0",
"ownerAddress": "0x52e7f17258368d7f9Ebd7bDf8d6869Bc4759aBA1",
"salt": "0"
}
},
"creator": {
"type": "api-key",
"actorId": "0199dfe1-0000-7000-8000-000000000009",
"id": "0199dfe1-0000-7000-8000-000000000010",
"metadata": {
"version": 1,
"name": "Workspace backend"
}
},
"installations": [
{
"id": "0199dfe1-0000-7000-8000-000000000013",
"chainId": "eip155:11155111",
"status": "pending",
"authorization": {
"version": 1,
"entityId": 142534698,
"signerAddress": "0x7838CE7D0AC8943A2fAA4e8ab8ae901b05eA7A03",
"permissions": [
{
"type": "root"
}
],
"allowSignatures": false,
"validAfter": 1792031945,
"validUntil": 1792035545
},
"installTransactionHash": null,
"uninstallTransactionHash": null
}
]
}
```
## Parameters [#parameters]
### namespace [#namespace]
Type: `"eip155"`. Required. The implemented chain namespace.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.create({
namespace: "eip155", // [!code focus]
walletId: "0199dfe1-0000-7000-8000-000000000001",
metadata: { version: 1, name: "Local agent" },
signer: { custody: "namera-managed", provider: "1claw", algorithm: "secp256k1" },
onchain: {
installations: [
{
chainId: "eip155:11155111",
validAfter: Math.floor(Date.now() / 1000),
validUntil: Math.floor(Date.now() / 1000) + 3600,
permissions: [{ type: "root" }],
allowSignatures: false,
},
],
},
policies: [],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### walletId [#walletid]
Type: `string`. Required. Existing account UUID in the same workspace. Account ownership and session custody are independent.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.create({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001", // [!code focus]
metadata: { version: 1, name: "Local agent" },
signer: { custody: "namera-managed", provider: "1claw", algorithm: "secp256k1" },
onchain: {
installations: [
{
chainId: "eip155:11155111",
validAfter: Math.floor(Date.now() / 1000),
validUntil: Math.floor(Date.now() / 1000) + 3600,
permissions: [{ type: "root" }],
allowSignatures: false,
},
],
},
policies: [],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### metadata [#metadata]
Type: `object`. Required. Session display metadata: `version: 1`, a required `name`, and optional `description` and `logo`.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.create({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
metadata: { version: 1, name: "Local agent" }, // [!code focus]
signer: { custody: "namera-managed", provider: "1claw", algorithm: "secp256k1" },
onchain: {
installations: [
{
chainId: "eip155:11155111",
validAfter: Math.floor(Date.now() / 1000),
validUntil: Math.floor(Date.now() / 1000) + 3600,
permissions: [{ type: "root" }],
allowSignatures: false,
},
],
},
policies: [],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### signer [#signer]
Type: `object`. Required. Use `{ custody: "namera-managed", provider: "1claw", algorithm: "secp256k1" }`, or `{ custody: "local", algorithm: "secp256k1", publicKey }`. The local public key must be uncompressed, beginning with `0x04` and containing 65 bytes. Keep the corresponding private key in your applicationβs secure signer store.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.create({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
metadata: { version: 1, name: "Local agent" },
signer: { custody: "namera-managed", provider: "1claw", algorithm: "secp256k1" }, // [!code focus]
onchain: {
installations: [
{
chainId: "eip155:11155111",
validAfter: Math.floor(Date.now() / 1000),
validUntil: Math.floor(Date.now() / 1000) + 3600,
permissions: [{ type: "root" }],
allowSignatures: false,
},
],
},
policies: [],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### onchain [#onchain]
Type: `object`. Required. Contains at least one installation; each network may appear once.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.create({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
metadata: { version: 1, name: "Local agent" },
signer: { custody: "namera-managed", provider: "1claw", algorithm: "secp256k1" },
onchain: {
// [!code focus]
installations: [
{
chainId: "eip155:11155111",
validAfter: Math.floor(Date.now() / 1000),
validUntil: Math.floor(Date.now() / 1000) + 3600,
permissions: [{ type: "root" }],
allowSignatures: false,
},
],
},
policies: [],
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
#### onchain.installations [#onchaininstallations]
Type: `readonly object[]`. Required. Each entry specifies `chainId` (a supported CAIP-2 network ID), `validAfter` and `validUntil` (Unix seconds), `permissions` (onchain permission definitions), and optional `allowSignatures` (defaults to `false`). Expiry must follow the start time and remain in the future at admission. Amount allowances are `bigint` values in token base units. `root` grants unrestricted account authority and cannot be combined with other permissions.
#### onchain.installations[].chainId [#onchaininstallationschainid]
Type: `SupportedEvmChainId`. Required. The supported CAIP-2 network, such as `eip155:11155111`. Each network may appear once.
#### onchain.installations[].validAfter [#onchaininstallationsvalidafter]
Type: `number`. Required. Nonnegative Unix timestamp in seconds at which transaction authority begins.
#### onchain.installations[].validUntil [#onchaininstallationsvaliduntil]
Type: `number`. Required. Unix timestamp in seconds after `validAfter`, still in the future at admission. Each network has its own expiry.
#### onchain.installations[].permissions [#onchaininstallationspermissions]
Type: `readonly EvmSessionPermission[]`. Required and nonempty. Choose onchain permissions such as native-token or ERC-20 allowances, allowed contracts/functions, and gas limits. Allowances are bigint base-unit amounts, not token display units. Root authority is exclusive and unrestricted. See [Permissions](https://namera.ai/docs/sdk/permissions).
#### onchain.installations[].allowSignatures [#onchaininstallationsallowsignatures]
Type: `boolean`. Optional; defaults to `false`. Enables onchain ERC-1271 signature authority. Transaction spending and time hooks do not constrain existing signature authority; uninstall it to remove that authority onchain. Namera signing also requires an API signature policy.
### policies [#policies]
Type: `readonly object[]`. Required. Session-level API signature policies. An empty array adds no API signature policy; transaction authority comes from installed onchain permissions. Signature use additionally requires explicit onchain signature authority.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.create({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
metadata: { version: 1, name: "Local agent" },
signer: { custody: "namera-managed", provider: "1claw", algorithm: "secp256k1" },
onchain: {
installations: [
{
chainId: "eip155:11155111",
validAfter: Math.floor(Date.now() / 1000),
validUntil: Math.floor(Date.now() / 1000) + 3600,
permissions: [{ type: "root" }],
allowSignatures: false,
},
],
},
policies: [], // [!code focus]
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
#### policies[].type and policies[].version [#policiestype-and-policiesversion]
Type: `"evm.signature" | "evm.time-window" | "evm.chain-allowlist"`, and `1`. Required for each policy. Each policy type may appear once. Creation accepts configuration only; persisted `id` and `appliesTo` fields are assigned by Namera.
#### policies[].allowedTypes and policies[].typedDataRules [#policiesallowedtypes-and-policiestypeddatarules]
Required for `evm.signature`: `allowedTypes` is a nonempty unique array of `"message"` and/or `"typed-data"`. Optional `typedDataRules` is a nonempty array of rules with `chainId`, `verifyingContract`, and nonempty unique `primaryTypes`; `name` and `version` optionally restrict the typed-data domain. Omit rules to allow all typed data when that signature type is enabled. Rules constrain Namera requests, not direct signing with a caller-held key.
#### policies[].startsAt and policies[].expiresAt [#policiesstartsat-and-policiesexpiresat]
Required for `evm.time-window`. SDK values are `DateTime.Utc | null` for `startsAt` and `DateTime.Utc` for `expiresAt`; wire values are ISO date-time strings. Null start means no lower time bound. Expiry must follow a non-null start and remain in the future at admission. This policy restricts API signatures, not installed transaction authority.
#### policies[].chainIds [#policieschainids]
Required for `evm.chain-allowlist`: a nonempty unique array of supported CAIP-2 network IDs on which API signing is permitted. A chain allowlist does not itself grant signature authority.
## Behavior and errors [#behavior-and-errors]
Requires `session-key:create` and applies to any account in the API keyβs workspace. Local signers submit only a public key. Managed signers provision a dedicated 1Claw key; never submit provider credentials. Creation atomically grants the calling API-key actor access to the new session. The session and installations remain pending until explicit owner-approved installation is confirmed. Managed creation retries transient failures with an SDK-generated idempotency key. Local registration is not automatically retried; retain your signer if a response is lost. No private key is returned. `NETWORK_PAUSED`, billing limits, invalid permissions, duplicate signers, and expired validity windows can reject creation.
# sessionKeys.getActiveOperation
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/session-keys/get-active-operation
Recover an active installation or removal operation.
`namera.sessionKeys.getActiveOperation()` recover an active installation or removal operation.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.getActiveOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003",
chainId: "eip155:11155111",
kind: "install",
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns `operation: null` when there is no active operation for this actor and target. Otherwise the operation contains `operationId`, `status`, and `preparation`. An unexpired unsigned operation returns a fresh preparation using its original internal idempotency key; signed/submitted operations have `preparation: null`. The SDK never exposes the stored retry key.
```json
{
"operation": {
"operationId": "0199dfe1-0000-7000-8000-000000000014",
"status": "awaiting-signature",
"preparation": {
"operationId": "0199dfe1-0000-7000-8000-000000000014",
"namespace": "eip155",
"approval": "1claw",
"prepared": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"entryPointVersion": "0.7",
"entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"sponsorship": "alchemy-bso",
"context": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"account": "0x3333333333333333333333333333333333333333",
"block": {
"number": "0",
"hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "1970-01-01T00:00:00.000Z"
},
"calls": [
{
"to": "0x3333333333333333333333333333333333333333",
"value": "0",
"data": "0x1234"
}
],
"userOperation": {
"nonce": "0",
"gas": {
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"paymasterVerificationGasLimit": "0",
"paymasterPostOpGasLimit": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0"
},
"paymaster": null
},
"simulation": {
"userOperation": {
"source": "eth_estimateUserOperationGas",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "1000000000",
"maxPriorityFeePerGas": "1"
},
"calls": {
"source": "viem.simulateCalls",
"results": [
{
"status": "success",
"returnData": "0x",
"gasUsed": "0"
}
],
"assetChanges": [],
"transfers": []
}
}
},
"userOperation": {
"sender": "0x3333333333333333333333333333333333333333",
"nonce": "0",
"callData": "0x",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0",
"signature": "0x"
},
"billing": {
"executionMeter": "execution.testnet",
"sponsorship": null
}
},
"expiresAt": "2026-10-15T02:44:05.075Z"
}
}
}
```
## Parameters [#parameters]
### sessionKeyId [#sessionkeyid]
Type: `string`. Required. Session UUID. Requires session read access to resolve the installation.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.getActiveOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003", // [!code focus]
chainId: "eip155:11155111",
kind: "install",
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### chainId [#chainid]
Type: `SupportedEvmChainId`. Required. Configured CAIP-2 network ID.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.getActiveOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003",
chainId: "eip155:11155111", // [!code focus]
kind: "install",
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### kind [#kind]
Type: `"install" | "uninstall"`. Required. The operation type you want to recover.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.getActiveOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003",
chainId: "eip155:11155111",
kind: "install", // [!code focus]
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Behavior and errors [#behavior-and-errors]
Requires `session-key:read`; recovering an unsigned preparation also requires its install/uninstall permission. API keys recover only their own operations. If `preparation` is present, review it and explicitly approve. If the operation is signed or submitted, poll it. Cancel an unsigned operation before deliberately preparing a replacement. Recovery does not create or install a new session.
# sessionKeys.getOperation
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/session-keys/get-operation
Read the status of an installation or removal operation.
`namera.sessionKeys.getOperation()` read the status of an installation or removal operation.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.getOperation("0199dfe1-0000-7000-8000-000000000014");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns `operationId` and `status`: `awaiting-signature`, `signed`, `submitted`, `confirmed`, `failed`, `expired`, or `cancelled`. Only `confirmed` establishes successful receipt confirmation.
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000000014",
"status": "confirmed"
}
```
## Parameters [#parameters]
### operationId [#operationid]
Type: `string`. Required. Resource UUID returned by creation, preparation, or recovery; not an address or transaction hash.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.getOperation("0199dfe1-0000-7000-8000-000000000014"); // [!code focus]
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Behavior and errors [#behavior-and-errors]
Requires `session-key:read`. API keys can poll only operations initiated by that same actor. `OPERATION_UNAVAILABLE` covers missing, foreign-workspace, and other-actor operations. A missing receipt leaves an operation pending; do not start another installation simply because polling is slow.
# Get Session Key
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/session-keys/get-session-key
Read a session key and its network installations.
`namera.sessionKeys.get(sessionKeyId)` returns the key, its account, creator, and installations.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.get("0199dfe1-0000-7000-8000-000000000002");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
- **`id`** (`string`): Session-key ID.
- **`organizationId`** (`string`): Owning organization.
- **`walletId`** (`string`): Account ID.
- **`signingKeyId`** (`string`): Signing-key identity.
- **`namespace`** (`"eip155"`): Chain namespace.
- **`metadata`** (`object`): version and name, with optional logo and description.
- **`policies`** (`readonly Policy[]`): Additional API policies.
- **`policyHash`** (`string`): Stored policy hash.
- **`status`** (`"pending" | "active" | "revoking" | "revoked"`): Session lifecycle status.
- **`revokedAt`** (`DateTime.Utc | null`): Revocation time, if revoked.
- **`createdAt`** (`DateTime.Utc`): Creation time.
- **`signer`** (`object`): Public signer identity and custody. No private key.
- **`wallet`** (`WalletResponse`): Complete account record.
- **`creator`** (`object`): Human member/user/role details, or an API-key descriptor with `type`, `actorId`, `id`, and `metadata`.
- **`installations`** (`readonly Installation[]`): Each has id, chainId, status, authorization, installTransactionHash, and uninstallTransactionHash. Authorization includes permissions, signature authority, and validity timestamps.
### Example Response [#example-response]
```json
{
"id": "0199dfe1-0000-7000-8000-000000000002",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"signingKeyId": "0199dfe1-0000-7000-8000-000000000006",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Example session",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "Send 0.001 test ETH on Base Sepolia"
},
"policies": [],
"policyHash": "1111111111111111111111111111111111111111111111111111111111111111",
"status": "active",
"revokedAt": null,
"createdAt": "2026-10-11T09:05:00.000Z",
"signer": {
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1",
"publicKey": "0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"metadata": {
"version": 1,
"name": "Example account",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "SDK test account"
},
"status": "active",
"namespace": "eip155",
"address": "0x1111111111111111111111111111111111111111",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000005",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "7702",
"delegationVersion": "v1.1.0"
},
"createdAt": "2026-10-11T09:00:00.000Z",
"updatedAt": "2026-10-11T09:00:00.000Z"
},
"creator": {
"organizationMember": {
"id": "0199dfe1-0000-7000-8000-000000000007",
"userId": "0199dfe1-0000-7000-8000-000000000008",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"organizationRoleId": "0199dfe1-0000-7000-8000-000000000009",
"joinedAt": "2026-10-11T08:00:00.000Z"
},
"user": {
"id": "0199dfe1-0000-7000-8000-000000000008",
"email": "developer@example.com",
"emailVerified": true,
"metadata": {
"version": 1,
"name": "Example developer",
"image": {
"type": "emoji",
"value": "π€"
}
},
"lastLoginAt": "2026-10-11T08:55:00.000Z"
},
"organizationRole": {
"id": "0199dfe1-0000-7000-8000-000000000009",
"key": "developer",
"metadata": {
"version": 1,
"name": "Developer",
"logo": {
"type": "emoji",
"value": "π»"
},
"description": "Manage test accounts and session keys"
},
"type": "custom",
"permissions": [
"wallet:read",
"wallet:create",
"session-key:read",
"session-key:create",
"api-key:create"
],
"systemRoleId": null
}
},
"installations": [
{
"id": "0199dfe1-0000-7000-8000-000000000010",
"chainId": "eip155:84532",
"status": "installed",
"authorization": {
"version": 1,
"entityId": 1,
"signerAddress": "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf",
"permissions": [
{
"type": "contract-access",
"address": "0x2222222222222222222222222222222222222222"
},
{
"type": "native-token-transfer",
"allowance": "1000000000000000"
}
],
"allowSignatures": false,
"validAfter": 1791709200,
"validUntil": 1794387600
},
"installTransactionHash": "0x2222222222222222222222222222222222222222222222222222222222222222",
"uninstallTransactionHash": null
}
]
}
```
## Parameters [#parameters]
### sessionKeyId [#sessionkeyid]
- **Type:** `string`
- **Required**
The session-key UUID returned by `sessionKeys.list()` or `sessionKeys.get()`.
This identifies the delegated session, not its signing key or network installation.
Execution and signing require an active grant for this key. Management reads may
instead use explicit workspace `session-key:read` permission.
For execution or signing, choose a key belonging to `walletId` with a confirmed
installation on `chainId` and permissions that allow the requested operation.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.get("0199dfe1-0000-7000-8000-000000000002"); // [!code focus]
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Errors [#errors]
`SESSION_KEY_NOT_FOUND` means the key does not exist or is not available to your credential. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors)
for authentication, transport, and contract errors.
# List Session Keys
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/session-keys/list-session-keys
Read authorized session keys, optionally filtered by account.
`namera.sessionKeys.list(options?)` lists session keys available to your credential.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.list({ walletId: "0199dfe1-0000-7000-8000-000000000001" });
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
An array of complete records. An empty array means no matching resources are available. The method is not paginated.
- **`id`** (`string`): Session-key ID.
- **`organizationId`** (`string`): Owning organization.
- **`walletId`** (`string`): Account ID.
- **`signingKeyId`** (`string`): Signing-key identity.
- **`namespace`** (`"eip155"`): Chain namespace.
- **`metadata`** (`object`): version and name, with optional logo and description.
- **`policies`** (`readonly Policy[]`): Additional API policies.
- **`policyHash`** (`string`): Stored policy hash.
- **`status`** (`"pending" | "active" | "revoking" | "revoked"`): Session lifecycle status.
- **`revokedAt`** (`DateTime.Utc | null`): Revocation time, if revoked.
- **`createdAt`** (`DateTime.Utc`): Creation time.
- **`signer`** (`object`): Public signer identity and custody. No private key.
- **`wallet`** (`WalletResponse`): Complete account record.
- **`creator`** (`object`): Human member/user/role details, or an API-key descriptor with `type`, `actorId`, `id`, and `metadata`.
- **`installations`** (`readonly Installation[]`): Each has id, chainId, status, authorization, installTransactionHash, and uninstallTransactionHash. Authorization includes permissions, signature authority, and validity timestamps.
### Example Response [#example-response]
```json
[
{
"id": "0199dfe1-0000-7000-8000-000000000002",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"signingKeyId": "0199dfe1-0000-7000-8000-000000000006",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Example session",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "Send 0.001 test ETH on Base Sepolia"
},
"policies": [],
"policyHash": "1111111111111111111111111111111111111111111111111111111111111111",
"status": "active",
"revokedAt": null,
"createdAt": "2026-10-11T09:05:00.000Z",
"signer": {
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1",
"publicKey": "0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000000001",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"metadata": {
"version": 1,
"name": "Example account",
"logo": {
"type": "emoji",
"value": "π"
},
"description": "SDK test account"
},
"status": "active",
"namespace": "eip155",
"address": "0x1111111111111111111111111111111111111111",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000000005",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "7702",
"delegationVersion": "v1.1.0"
},
"createdAt": "2026-10-11T09:00:00.000Z",
"updatedAt": "2026-10-11T09:00:00.000Z"
},
"creator": {
"organizationMember": {
"id": "0199dfe1-0000-7000-8000-000000000007",
"userId": "0199dfe1-0000-7000-8000-000000000008",
"organizationId": "0199dfe1-0000-7000-8000-000000000004",
"organizationRoleId": "0199dfe1-0000-7000-8000-000000000009",
"joinedAt": "2026-10-11T08:00:00.000Z"
},
"user": {
"id": "0199dfe1-0000-7000-8000-000000000008",
"email": "developer@example.com",
"emailVerified": true,
"metadata": {
"version": 1,
"name": "Example developer",
"image": {
"type": "emoji",
"value": "π€"
}
},
"lastLoginAt": "2026-10-11T08:55:00.000Z"
},
"organizationRole": {
"id": "0199dfe1-0000-7000-8000-000000000009",
"key": "developer",
"metadata": {
"version": 1,
"name": "Developer",
"logo": {
"type": "emoji",
"value": "π»"
},
"description": "Manage test accounts and session keys"
},
"type": "custom",
"permissions": [
"wallet:read",
"wallet:create",
"session-key:read",
"session-key:create",
"api-key:create"
],
"systemRoleId": null
}
},
"installations": [
{
"id": "0199dfe1-0000-7000-8000-000000000010",
"chainId": "eip155:84532",
"status": "installed",
"authorization": {
"version": 1,
"entityId": 1,
"signerAddress": "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf",
"permissions": [
{
"type": "contract-access",
"address": "0x2222222222222222222222222222222222222222"
},
{
"type": "native-token-transfer",
"allowance": "1000000000000000"
}
],
"allowSignatures": false,
"validAfter": 1791709200,
"validUntil": 1794387600
},
"installTransactionHash": "0x2222222222222222222222222222222222222222222222222222222222222222",
"uninstallTransactionHash": null
}
]
}
]
```
## Parameters [#parameters]
The optional `options` object defaults to `{}`.
### walletId [#walletid]
- **Type:** `string`
- **Optional**
Filters keys to one account UUID. Omit options or pass `{}` to list all keys available to your credential across accounts. This does not broaden its grants.
```ts title="index.ts"
import { namera } from "./client";
const sessions = await namera.sessionKeys.list({
walletId: "0199dfe1-0000-7000-8000-000000000001", // [!code focus]
});
if (!sessions.success) throw new Error(sessions.error.message);
console.log(sessions.data);
```
## Errors [#errors]
A filtered request can return `WALLET_NOT_FOUND`. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors)
for authentication, transport, and contract errors.
# sessionKeys.prepareOperation
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/session-keys/prepare-operation
Prepare installation or removal on one configured network.
`namera.sessionKeys.prepareOperation()` prepare installation or removal on one configured network.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.prepareOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003",
chainId: "eip155:11155111",
kind: "install",
sponsor: true,
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns `operationId`, `namespace`, `approval`, `prepared`, and `expiresAt`. `approval` is `"1claw"` or `"passkey"`; passkey responses also include WebAuthn `options`. Preparation contains the exact stored installation/removal call, simulation, and gas information, but no owner signature.
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000000014",
"namespace": "eip155",
"approval": "1claw",
"prepared": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"entryPointVersion": "0.7",
"entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"sponsorship": "alchemy-bso",
"context": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"account": "0x3333333333333333333333333333333333333333",
"block": {
"number": "0",
"hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "1970-01-01T00:00:00.000Z"
},
"calls": [
{
"to": "0x3333333333333333333333333333333333333333",
"value": "0",
"data": "0x1234"
}
],
"userOperation": {
"nonce": "0",
"gas": {
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"paymasterVerificationGasLimit": "0",
"paymasterPostOpGasLimit": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0"
},
"paymaster": null
},
"simulation": {
"userOperation": {
"source": "eth_estimateUserOperationGas",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "1000000000",
"maxPriorityFeePerGas": "1"
},
"calls": {
"source": "viem.simulateCalls",
"results": [
{
"status": "success",
"returnData": "0x",
"gasUsed": "0"
}
],
"assetChanges": [],
"transfers": []
}
}
},
"userOperation": {
"sender": "0x3333333333333333333333333333333333333333",
"nonce": "0",
"callData": "0x",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0",
"signature": "0x"
},
"billing": {
"executionMeter": "execution.testnet",
"sponsorship": null
}
},
"expiresAt": "2026-10-15T02:44:05.075Z"
}
```
Passkey approval uses this shape:
```json
{
"operationId": "0199dfe1-0000-7000-8000-000000000021",
"namespace": "eip155",
"options": {
"challenge": "ERERERERERERERERERERERERERERERERERERERERERE",
"rpId": "app.example.com",
"timeout": 300000,
"allowCredentials": [
{
"id": "fH9q_W4I4NAClGWOrbumZv4mrefSBfKPdY2UFfTKvcI",
"type": "public-key"
}
],
"userVerification": "required"
},
"prepared": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"entryPointVersion": "0.7",
"entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
"sponsorship": "alchemy-bso",
"context": {
"version": 1,
"namespace": "eip155",
"chainId": "eip155:11155111",
"account": "0x3333333333333333333333333333333333333333",
"block": {
"number": "0",
"hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "1970-01-01T00:00:00.000Z"
},
"calls": [
{
"to": "0x3333333333333333333333333333333333333333",
"value": "0",
"data": "0x1234"
}
],
"userOperation": {
"nonce": "0",
"gas": {
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"paymasterVerificationGasLimit": "0",
"paymasterPostOpGasLimit": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0"
},
"paymaster": null
},
"simulation": {
"userOperation": {
"source": "eth_estimateUserOperationGas",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "1000000000",
"maxPriorityFeePerGas": "1"
},
"calls": {
"source": "viem.simulateCalls",
"results": [
{
"status": "success",
"returnData": "0x",
"gasUsed": "0"
}
],
"assetChanges": [],
"transfers": []
}
}
},
"userOperation": {
"sender": "0x3333333333333333333333333333333333333333",
"nonce": "0",
"callData": "0x",
"callGasLimit": "0",
"verificationGasLimit": "0",
"preVerificationGas": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0",
"signature": "0x"
},
"billing": {
"executionMeter": "execution.testnet",
"sponsorship": null
}
},
"expiresAt": "2026-10-15T02:44:06.347Z"
}
```
## Parameters [#parameters]
### sessionKeyId [#sessionkeyid]
Type: `string`. Required. Session UUID. The SDK reads this session to resolve its account owner and matching installation. Requires session read access.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.prepareOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003", // [!code focus]
chainId: "eip155:11155111",
kind: "install",
sponsor: true,
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### chainId [#chainid]
Type: `SupportedEvmChainId`. Required. Configured CAIP-2 network ID, such as `eip155:11155111`. This is not a numeric chain ID.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.prepareOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003",
chainId: "eip155:11155111", // [!code focus]
kind: "install",
sponsor: true,
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### kind [#kind]
Type: `"install" | "uninstall"`. Required. Choose installation or removal. Removal can target an installed network of an active or revoking session.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.prepareOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003",
chainId: "eip155:11155111",
kind: "install", // [!code focus]
sponsor: true,
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
### sponsor [#sponsor]
Type: `boolean`. Optional; defaults to `true`. Whether to request gas sponsorship. Billing allowances still apply. Self-funded approval requires independent gas consent through the owner-approval validation helper.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.prepareOperation({
sessionKeyId: "0199dfe1-0000-7000-8000-000000000003",
chainId: "eip155:11155111",
kind: "install",
sponsor: true, // [!code focus]
});
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Behavior and errors [#behavior-and-errors]
Requires `session-key:read` plus `session-key:install` or `session-key:uninstall`. Preparation never signs or submits. The SDK generates and reuses one idempotency key across transient retries. A new call gets a new key; use `getActiveOperation()` to recover an interrupted operation. `OPERATION_BUSY` means another owner operation occupies that account/network. `INVALID_TRANSITION` means the session or installation cannot enter the requested transition. Callers must validate preparations against independently reviewed authority before approval; these are low-level transport methods, like execution prepare/complete.
# sessionKeys.revoke
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/session-keys/revoke-session-key
Revoke a sessionβs Namera access and grants.
`namera.sessionKeys.revoke()` revoke a sessionβs Namera access and grants.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY` on your backend. IDs and responses below are illustrative fixtures; replace IDs with your own resources.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.revoke("0199dfe1-0000-7000-8000-000000001000");
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
Returns the complete session. Never-installed sessions may become `revoked` immediately; installed or signed authority remains `revoking` until removal/reconciliation finishes. This fixture has an installed network, so server access is revoked while onchain removal is still required.
```json
{
"id": "0199dfe1-0000-7000-8000-000000001000",
"organizationId": "0199dfe1-0000-7000-8000-000000001001",
"walletId": "0199dfe1-0000-7000-8000-000000001002",
"signingKeyId": "0199dfe1-0000-7000-8000-000000001003",
"namespace": "eip155",
"metadata": {
"version": 1,
"name": "Local agent"
},
"policies": [],
"policyHash": "9Z4ZzPfiQ4hIUpSXTY_nQ2E9-kjd2w_5wbLwIj7visI",
"status": "revoking",
"revokedAt": "2026-10-15T02:57:34.211Z",
"createdAt": "2026-10-15T02:57:32.375Z",
"signer": {
"custody": "local",
"algorithm": "secp256k1",
"publicKey": "0x04c70cd5e6b1350f36bb3f47e4c50f276178a843ddc457189b962b660b81945ccee5bd6e75bbf22348c1ece286baeec6776e5cc66206f2b5de96cf0c8a0ca407e1"
},
"wallet": {
"id": "0199dfe1-0000-7000-8000-000000001002",
"organizationId": "0199dfe1-0000-7000-8000-000000001001",
"metadata": {
"version": 1,
"name": "Managed owner"
},
"status": "active",
"namespace": "eip155",
"address": "0x3333333333333333333333333333333333333333",
"owner": {
"signingKeyId": "0199dfe1-0000-7000-8000-000000001004",
"custody": "namera-managed",
"provider": "1claw",
"algorithm": "secp256k1"
},
"createdAt": "2026-10-15T02:57:32.345Z",
"updatedAt": "2026-10-15T02:57:32.345Z",
"implementation": "alchemy-modular-v2",
"data": {
"version": 1,
"modularAccountVersion": "2.0.0",
"validatorType": "ecdsa_secp256k1",
"entryPointVersion": "0.7",
"accountMode": "factory",
"factoryVersion": "2.0.0",
"implementationVersion": "v1.0.0",
"ownerAddress": "0x90C59223ac50061f5204826078944ec41bc56e0d",
"salt": "0"
}
},
"creator": {
"organizationMember": {
"id": "0199dfe1-0000-7000-8000-000000001005",
"userId": "0199dfe1-0000-7000-8000-000000001006",
"organizationId": "0199dfe1-0000-7000-8000-000000001001",
"organizationRoleId": "0199dfe1-0000-7000-8000-000000001007",
"joinedAt": "2026-10-15T02:57:32.244Z"
},
"user": {
"id": "0199dfe1-0000-7000-8000-000000001006",
"email": "0199dfe1-0000-7000-8000-000000001008@example.com",
"emailVerified": true,
"metadata": {
"version": 1
},
"lastLoginAt": "2026-10-15T02:57:32.211Z"
},
"organizationRole": {
"id": "0199dfe1-0000-7000-8000-000000001007",
"key": "owner",
"permissions": [
"organization:read",
"organization:update",
"member:read",
"member:update",
"member:remove",
"invitation:read",
"invitation:create",
"invitation:cancel",
"role:read",
"role:create",
"role:update",
"role:delete",
"billing:read",
"billing:update",
"billing:cancel",
"wallet:read",
"wallet:create",
"wallet:update",
"session-key:read",
"session-key:create",
"session-key:revoke",
"api-key:read",
"api-key:create",
"api-key:revoke",
"execution:read",
"mcp-authorization:read",
"mcp-authorization:create",
"mcp-authorization:revoke",
"cli-authorization:read",
"cli-authorization:create",
"cli-authorization:revoke"
],
"metadata": {
"version": 1,
"name": "Owner",
"description": "Organization owner with full access"
},
"type": "system",
"systemRoleId": "0199dfe1-0000-7000-8000-000000001009"
}
},
"installations": [
{
"id": "0199dfe1-0000-7000-8000-000000001010",
"chainId": "eip155:11155111",
"status": "installed",
"authorization": {
"version": 1,
"entityId": 94541820,
"signerAddress": "0xAB592704Fde287292b3a886Db80C0B6e7AC6DAdc",
"permissions": [
{
"type": "root"
}
],
"allowSignatures": false,
"validAfter": 1792033052,
"validUntil": 1792036652
},
"installTransactionHash": "0x2222222222222222222222222222222222222222222222222222222222222222",
"uninstallTransactionHash": null
}
]
}
```
## Parameters [#parameters]
### sessionKeyId [#sessionkeyid]
Type: `string`. Required. Resource UUID returned by creation, preparation, or recovery; not an address or transaction hash.
```ts title="index.ts"
import { namera } from "./client";
const result = await namera.sessionKeys.revoke("0199dfe1-0000-7000-8000-000000001000"); // [!code focus]
if (!result.success) throw new Error(result.error.message);
console.log(result.data);
```
## Behavior and errors [#behavior-and-errors]
Requires `session-key:revoke` and can target any session in this workspace. Revocation atomically revokes grants and cancels unsigned installation requests. It does not erase onchain authority. Use `prepareOperation({ kind: "uninstall", ... })` and explicit approval for each installed network, then track confirmation. Signed operations must still reconcile.
# Sign
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/signatures/sign
Sign a UTF-8 message or EIP-712 typed data.
`namera.sign(request)` prepares, validates, and completes a signature using the selected session key. It does not send a transaction.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
console.log(signed.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
- **`namespace`** (`"eip155"`): Chain namespace.
- **`walletId`** (`string`): Account UUID.
- **`chainId`** (`SupportedEvmChainId`): Signing network.
- **`account`** (`` `0x${string}` ``): Smart-account address.
- **`signature`** (`` `0x${string}` ``): Smart-account signature, not a bare EOA signature.
- **`type`** (`"message" | "typed-data"`): Payload kind.
### Example Response [#example-response]
```json
{
"namespace": "eip155",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"chainId": "eip155:84532",
"account": "0x1111111111111111111111111111111111111111",
"signature": "0x0000000100111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111b",
"type": "message"
}
```
## Parameters [#parameters]
Pass a `SignRequest` object. The selected session needs installed signature authority and an API policy permitting the payload.
### namespace [#namespace]
- **Type:** `"eip155"`
- **Required**
The blockchain namespace. Use `"eip155"` for every currently supported Namera
network. This is not a chain ID; select the specific network with `chainId`.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155", // [!code focus]
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
console.log(signed.data);
```
### walletId [#walletid]
- **Type:** `string`
- **Required**
The account UUID returned by `wallets.list()` or `wallets.get()`. Pass its `id`,
not its onchain `address`. The account must be accessible to the clientβs credential.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001", // [!code focus]
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
console.log(signed.data);
```
### sessionKeyId [#sessionkeyid]
- **Type:** `string`
- **Required**
The session-key UUID returned by `sessionKeys.list()` or `sessionKeys.get()`.
This identifies the delegated session, not its signing key or network installation.
Execution and signing require an active grant for this key. Management reads may
instead use explicit workspace `session-key:read` permission.
For execution or signing, choose a key belonging to `walletId` with a confirmed
installation on `chainId` and permissions that allow the requested operation.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002", // [!code focus]
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
console.log(signed.data);
```
### chainId [#chainid]
- **Type:** `SupportedEvmChainId`
- **Required**
The target network in CAIP-2 format. For Base Sepolia, use `"eip155:84532"`,
not `84532` or `"84532"`. Use the network on which the account will execute, sign, or verify the payload.
The SDK restricts this field to the [supported network IDs](https://namera.ai/docs/sdk/supported-networks).
Network availability is also checked by the API.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532", // [!code focus]
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
console.log(signed.data);
```
### type [#type]
- **Type:** `"message" | "typed-data"`
- **Required**
Selects the payload format. Use `message` with `"message"` or `typedData` with
`"typed-data"`. Do not supply both payload fields.
### message [#message]
- **Type:** `string`
- **Required when:** `type` is `"message"`
The exact UTF-8 text to sign or verify. Whitespace and capitalization are part of
the payload. A string such as `"0x1234"` is text, not raw bytes.
### typedData [#typeddata]
- **Type:** `EvmTypedData`
- **Required when:** `type` is `"typed-data"`
An EIP-712 payload containing `domain`, `types`, `primaryType`, and `message`.
Use the identical payload when verifying its signature.
```ts title="index.ts"
import type { EvmTypedData } from "@namera-ai/sdk";
const typedData = {
domain: {
// [!code focus:6]
name: "Namera Example",
version: "1",
chainId: 84532,
verifyingContract: "0x3333333333333333333333333333333333333333",
},
types: { Greeting: [{ name: "contents", type: "string" }] },
primaryType: "Greeting",
message: { contents: "Hello from Namera" },
} satisfies EvmTypedData;
```
#### typedData.domain [#typeddatadomain]
- **Type:** `EvmTypedData["domain"]`
- **Required**
The signing domain. Its fields are optional: `name` and `version` are strings;
`chainId` is a nonnegative integer; `verifyingContract` is a 20-byte address;
`salt` is a 32-byte hex value. Unlike the requestβs CAIP-2 `chainId`, this domain
uses a number such as `84532`. Use the domain expected by the verifying application.
#### typedData.types [#typeddatatypes]
- **Type:** `Record`
- **Required**
Definitions of the structs used by the payload. Struct names, field names, and
field types must be nonempty strings. Each struct needs at least one field.
#### typedData.primaryType [#typeddataprimarytype]
- **Type:** `string`
- **Required**
The root struct name from `types`, such as `"Greeting"`. It determines how the
message fields are encoded.
#### typedData.message [#typeddatamessage]
- **Type:** `Record`
- **Required**
Values matching the root struct. Use JSON-compatible values. Represent large
integers as decimal strings, not JavaScript `bigint`, to preserve precision.
#### Sign typed data [#sign-typed-data]
Use `type: "typed-data"` with the complete payload. The sessionβs signature policy
must permit its domain and primary type. Replace the domainβs contract address
with the one expected by your application.
```ts title="index.ts"
import type { EvmTypedData } from "@namera-ai/sdk";
import { namera } from "./client";
const typedData = {
domain: {
name: "Namera Example",
version: "1",
chainId: 84532,
verifyingContract: "0x3333333333333333333333333333333333333333",
},
types: {
Greeting: [{ name: "contents", type: "string" }],
},
primaryType: "Greeting",
message: { contents: "Hello from Namera" },
} satisfies EvmTypedData;
```
## Errors [#errors]
Signature policy, authorization, billing, and signing failures return `success: false`. Prepared-payload or signature validation failures use `kind: "signer"`. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for shared authentication, transport, and contract errors.
Guides: [Sign Messages](https://namera.ai/docs/sdk/guides/signing/sign-messages) and [Sign Typed Data](https://namera.ai/docs/sdk/guides/signing/sign-typed-data).
# Verify Signature
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/reference/signatures/verify-signature
Verify a smart-account signature against its original payload.
`namera.verifySignature(request)` performs read-only verification. It requires access to the account, but no session-key ID.
## Usage [#usage]
Install `@namera-ai/sdk` and set `NAMERA_API_KEY`. Replace example IDs with resources available to your credential.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
const verification = await namera.verifySignature({
namespace: "eip155",
walletId: signed.data.walletId,
chainId: signed.data.chainId,
type: "message",
message,
signature: signed.data.signature,
});
if (!verification.success) throw new Error(verification.error.message);
console.log(verification.data);
```
```ts title="client.ts"
import { NameraClient } from "@namera-ai/sdk";
export const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
```
## Returns [#returns]
API methods return a `Promise>`. When `success` is `true`,
`data` contains the value described below and `error` is `null`. On failure,
`data` is `null` and `error` describes the failure.
The JSON example shows the complete successful `data`, with illustrative values.
Date-time values use ISO strings in JSON; bigint values use decimal strings.
See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for the error shape.
- **`namespace`** (`"eip155"`): Chain namespace.
- **`walletId`** (`string`): Account UUID.
- **`chainId`** (`SupportedEvmChainId`): Verification network.
- **`account`** (`` `0x${string}` ``): Smart-account address.
- **`valid`** (`boolean`): Whether the account accepts this signature for the payload.
- **`type`** (`"message" | "typed-data"`): Payload kind.
### Example Response [#example-response]
```json
{
"namespace": "eip155",
"walletId": "0199dfe1-0000-7000-8000-000000000001",
"chainId": "eip155:84532",
"account": "0x1111111111111111111111111111111111111111",
"valid": true,
"type": "message"
}
```
## Parameters [#parameters]
Pass a `VerifySignatureRequest` object. No session-key ID is needed. For `type: "typed-data"`, provide `typedData` instead of `message`.
### namespace [#namespace]
- **Type:** `"eip155"`
- **Required**
The blockchain namespace. Use `"eip155"` for every currently supported Namera
network. This is not a chain ID; select the specific network with `chainId`.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155", // [!code focus]
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
const verification = await namera.verifySignature({
namespace: "eip155",
walletId: signed.data.walletId,
chainId: signed.data.chainId,
type: "message",
message,
signature: signed.data.signature,
});
if (!verification.success) throw new Error(verification.error.message);
console.log(verification.data);
```
### walletId [#walletid]
- **Type:** `string`
- **Required**
The account UUID returned by `wallets.list()` or `wallets.get()`. Pass its `id`,
not its onchain `address`. The account must be accessible to the clientβs credential.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001", // [!code focus]
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
const verification = await namera.verifySignature({
namespace: "eip155",
walletId: signed.data.walletId,
chainId: signed.data.chainId,
type: "message",
message,
signature: signed.data.signature,
});
if (!verification.success) throw new Error(verification.error.message);
console.log(verification.data);
```
### chainId [#chainid]
- **Type:** `SupportedEvmChainId`
- **Required**
The target network in CAIP-2 format. For Base Sepolia, use `"eip155:84532"`,
not `84532` or `"84532"`. Use the network on which the account will execute, sign, or verify the payload.
The SDK restricts this field to the [supported network IDs](https://namera.ai/docs/sdk/supported-networks).
Network availability is also checked by the API.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532", // [!code focus]
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
const verification = await namera.verifySignature({
namespace: "eip155",
walletId: signed.data.walletId,
chainId: signed.data.chainId,
type: "message",
message,
signature: signed.data.signature,
});
if (!verification.success) throw new Error(verification.error.message);
console.log(verification.data);
```
### type [#type]
- **Type:** `"message" | "typed-data"`
- **Required**
Selects the payload format. Use `message` with `"message"` or `typedData` with
`"typed-data"`. Do not supply both payload fields.
### message [#message]
- **Type:** `string`
- **Required when:** `type` is `"message"`
The exact UTF-8 text to sign or verify. Whitespace and capitalization are part of
the payload. A string such as `"0x1234"` is text, not raw bytes.
### typedData [#typeddata]
- **Type:** `EvmTypedData`
- **Required when:** `type` is `"typed-data"`
An EIP-712 payload containing `domain`, `types`, `primaryType`, and `message`.
Use the identical payload when verifying its signature.
```ts title="index.ts"
import type { EvmTypedData } from "@namera-ai/sdk";
const typedData = {
domain: {
// [!code focus:6]
name: "Namera Example",
version: "1",
chainId: 84532,
verifyingContract: "0x3333333333333333333333333333333333333333",
},
types: { Greeting: [{ name: "contents", type: "string" }] },
primaryType: "Greeting",
message: { contents: "Hello from Namera" },
} satisfies EvmTypedData;
```
#### typedData.domain [#typeddatadomain]
- **Type:** `EvmTypedData["domain"]`
- **Required**
The signing domain. Its fields are optional: `name` and `version` are strings;
`chainId` is a nonnegative integer; `verifyingContract` is a 20-byte address;
`salt` is a 32-byte hex value. Unlike the requestβs CAIP-2 `chainId`, this domain
uses a number such as `84532`. Use the domain expected by the verifying application.
#### typedData.types [#typeddatatypes]
- **Type:** `Record`
- **Required**
Definitions of the structs used by the payload. Struct names, field names, and
field types must be nonempty strings. Each struct needs at least one field.
#### typedData.primaryType [#typeddataprimarytype]
- **Type:** `string`
- **Required**
The root struct name from `types`, such as `"Greeting"`. It determines how the
message fields are encoded.
#### typedData.message [#typeddatamessage]
- **Type:** `Record`
- **Required**
Values matching the root struct. Use JSON-compatible values. Represent large
integers as decimal strings, not JavaScript `bigint`, to preserve precision.
### signature [#signature]
- **Type:** `` `0x${string}` ``
- **Required**
The complete signature returned by `sign()`, including its validation envelope. Do not strip it to a bare EOA signature. Supply the original payload, account, and network.
A successful request can return `valid: false`; only `data.valid: true` means the signature was accepted.
```ts title="index.ts"
import { namera } from "./client";
const message = "Hello from Namera";
const signed = await namera.sign({
namespace: "eip155",
walletId: "0199dfe1-0000-7000-8000-000000000001",
sessionKeyId: "0199dfe1-0000-7000-8000-000000000002",
chainId: "eip155:84532",
type: "message",
message,
});
if (!signed.success) throw new Error(signed.error.message);
const verification = await namera.verifySignature({
namespace: "eip155",
walletId: signed.data.walletId,
chainId: signed.data.chainId,
type: "message",
message,
signature: signed.data.signature, // [!code focus]
});
if (!verification.success) throw new Error(verification.error.message);
console.log(verification.data);
```
## Errors [#errors]
`VERIFICATION_FAILED` indicates verification could not be completed; `valid: false` is a completed check that rejected the signature. See [Handling Results and Errors](https://namera.ai/docs/sdk/handling-results-and-errors) for shared authentication, transport, and contract errors.
Guide: [Verify Signatures](https://namera.ai/docs/sdk/guides/signing/verify-signatures).
# Supported Networks
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/sdk/supported-networks
Choose a mainnet or testnet for your SDK calls.
Namera supports eight EVM networks. Use `namespace: "eip155"` and the full
`chainId` string when executing, simulating, or signing.
## Mainnets [#mainnets]
| Network | Chain ID |
| ------------ | -------------- |
| Ethereum | `eip155:1` |
| Base | `eip155:8453` |
| Arbitrum One | `eip155:42161` |
| OP Mainnet | `eip155:10` |
## Testnets [#testnets]
| Network | Chain ID |
| ---------------- | ----------------- |
| Ethereum Sepolia | `eip155:11155111` |
| Base Sepolia | `eip155:84532` |
| Arbitrum Sepolia | `eip155:421614` |
| OP Sepolia | `eip155:11155420` |
The [Getting Started](https://namera.ai/docs/sdk/getting-started) walkthrough uses **Base Sepolia**.
Fund the account with test ETH on that network before sending a transfer.
## Select a Network [#select-a-network]
Import `SupportedEvmChainId` from the SDK to type a network in your configuration:
```ts title="index.ts"
import { NameraClient, type SupportedEvmChainId } from "@namera-ai/sdk";
const namera = new NameraClient({
apiKey: process.env.NAMERA_API_KEY!,
});
const chainId: SupportedEvmChainId = "eip155:84532";
const result = await namera.sessionKeys.get("0199dfe1-0000-7000-8000-000000000002");
if (!result.success) throw new Error(result.error.message);
const installation = result.data.installations.find(
(entry) => entry.chainId === chainId && entry.status === "installed",
);
if (!installation) throw new Error("Install this session key on Base Sepolia first.");
```
Replace the example session-key ID with your own. An installation on one network
does not authorize another. Its validity period and permissions must also allow
your operation.
Changing `chainId` selects a network; it does not move funds between networks.
Use the recipient or contract address for the network you selected.
If a request returns `NETWORK_PAUSED`, wait for that network to be re-enabled
before submitting a new operation. You can still check existing submissions.
Next, learn how to [handle results and errors](https://namera.ai/docs/sdk/handling-results-and-errors).
# Why Namera
> Documentation index: [llms.txt](https://namera.ai/llms.txt).
Source: https://namera.ai/docs/why-namera
A brief primer on why we built Namera
Giving an agent the ability to act onchain sounds simple until you try to put
boundaries around it. The moment it can move funds, sign messages, or interact
with contracts, you need to decide what it should be allowed to do and what
should remain outside its control.
Namera is built around that question: how do you give an agent useful access to
a wallet without giving it the authority of the wallet owner?
## The Problem with Agent Wallets [#the-problem-with-agent-wallets]
Passing a wallet's private key through a `.env` file gets you to a working
integration quickly. But the key does not know which task the agent is carrying
out. If it controls the account, it can authorize whatever the account allows,
not just the operation you intended.
You can add checks to your application, but those checks are separate from the
authority of the key itself. A spending rule in a prompt is not a spending
limit on a wallet. Giving several agents the same owner key also makes it
harder to separate their access or withdraw permission from just one of them.
Moving the key behind an API changes where it is held. It does not, on its own,
define what each caller should be allowed to do. Key custody and delegated
permissions are different problems. Both need an explicit answer.
## What Namera Does Differently [#what-namera-does-differently]
Namera does not ask an agent to act as the account owner. It gives you a way to
issue scoped session keys and grant each integration access to the keys it needs.
Depending on the permissions you configure, you can restrict:
- which networks the session key can use
- which contracts and functions it can call
- which tokens it can transfer and how much it can spend
- how much native value and gas it can use
- when execution access starts and expires
- whether it can sign messages or typed data
The current EVM accounts use Alchemy Modular Account V2. Session permissions
are installed on the smart account with owner approval on each network.
Additional API policies narrow signature requests authorized through Namera. These are
separate layers: an API restriction is not automatically an onchain restriction.
The same distinction matters when withdrawing access. Revoking a session key
blocks its use through Namera. Removing its onchain permissions requires a
separate owner-approved operation on each network where it was installed.
Onchain signature authority is explicitly enabled and is not removed simply
because execution access expires.
Permissions limit authority, not judgment. An allowed transaction can still be
a bad decision. The goal is to define the access a task needs and avoid granting
more than that.
## Choose How You Hold Keys [#choose-how-you-hold-keys]
Account ownership and session-key custody are independent choices. A user-owned
passkey account or a 1Claw-managed account can use local or managed session keys.
With a local session key, your client holds the private key and signs locally.
With a managed session key, Namera requests signatures through 1Claw. Neither
choice turns the session key into an account owner; its installed permissions
and Namera authorization still determine what it can do.
## Designed to Work with Your Tools [#designed-to-work-with-your-tools]
You should not need a different permission model every time you change how an
agent connects. The [SDK](https://namera.ai/docs/sdk), [CLI](https://namera.ai/docs/cli), and [MCP](https://namera.ai/docs/mcp)
clients use the same grant-scoped execution and signing capabilities.
Use the SDK from a TypeScript application, the CLI from your terminal, or MCP
from a compatible agent client. The interface changes. The account, session
key, and permissions behind it stay the same.