Build or update the BlueBubbles external channel plugin for Moltbot (extension package, REST...
npx skills add getpara/ai-tooling --skill "para-wallet-operations"
Install specific skill from multi-skill repository
# Description
Create, manage, and sign with Para MPC wallets via REST API
# SKILL.md
name: para-wallet-operations
description: Create, manage, and sign with Para MPC wallets via REST API
Para Wallet Operations
Create and manage MPC (Multi-Party Computation) wallets via Para's REST API. The private key never exists in a single place, making Para ideal for AI agents that need to transact onchain.
MPC Security Model
Para uses Multi-Party Computation so the full private key never exists on any single machine:
- Key shares are distributed across independent parties
- When you sign, each party signs with their share and results are combined into a valid signature
- No single point of compromise can leak the private key
- Agents can sign transactions without ever having access to a full key
- Signatures are functionally equivalent to normal signatures from the blockchain's perspective
Setup
- Get an API key from developer.getpara.com
- Allowlist your server's IP address in the Para dashboard
- Set the environment variable:
export PARA_API_KEY="your-secret-api-key"
Base URLs
| Environment | URL |
|---|---|
| Beta (development) | https://api.beta.getpara.com |
| Production | https://api.getpara.com |
Authentication
Pass your API key in the X-API-Key header on every request:
X-API-Key: your_api_key
Content-Type: application/json
X-Request-Id: <uuid> (optional, for request tracing)
REST API Endpoints
Create Wallet
POST /v1/wallets
Creates a new MPC wallet for a user. Each combination of type + scheme + userIdentifier produces exactly one wallet.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | EVM, SOLANA, or COSMOS |
userIdentifier |
string | Yes | User identifier (email, phone, or custom ID) |
userIdentifierType |
string | Yes | EMAIL, PHONE, CUSTOM_ID, GUEST_ID, TELEGRAM, DISCORD, or TWITTER |
scheme |
string | No | Signature scheme: DKLS (EVM default), CGGMP, or ED25519 (Solana default) |
cosmosPrefix |
string | No | Bech32 prefix for Cosmos wallets |
EVM Example
curl -X POST https://api.beta.getpara.com/v1/wallets \
-H "Content-Type: application/json" \
-H "X-API-Key: $PARA_API_KEY" \
-d '{
"type": "EVM",
"userIdentifier": "[email protected]",
"userIdentifierType": "EMAIL"
}'
Solana Example
curl -X POST https://api.beta.getpara.com/v1/wallets \
-H "Content-Type: application/json" \
-H "X-API-Key: $PARA_API_KEY" \
-d '{
"type": "SOLANA",
"userIdentifier": "[email protected]",
"userIdentifierType": "EMAIL"
}'
Response (201 Created)
The wallet starts in creating status. You must poll until it reaches ready.
{
"id": "0a1b2c3d-4e5f-6789-abcd-ef0123456789",
"type": "EVM",
"scheme": "DKLS",
"status": "creating",
"createdAt": "2024-01-15T09:30:00Z"
}
Get Wallet
GET /v1/wallets/{walletId}
Retrieves the current status and details of a wallet.
curl https://api.beta.getpara.com/v1/wallets/0a1b2c3d-4e5f-6789-abcd-ef0123456789 \
-H "X-API-Key: $PARA_API_KEY"
Response (200 OK)
{
"id": "0a1b2c3d-4e5f-6789-abcd-ef0123456789",
"type": "EVM",
"scheme": "DKLS",
"status": "ready",
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f...",
"publicKey": "04a1b2c3d4e5f6...",
"createdAt": "2024-01-15T09:30:00Z"
}
Response Fields
| Field | Type | Description |
|---|---|---|
id |
string | Unique wallet identifier (UUID) |
type |
string | Blockchain network: EVM, SOLANA, or COSMOS |
scheme |
string | Signature scheme: DKLS, CGGMP, or ED25519 |
status |
string | creating or ready |
address |
string | Wallet address (present when status is ready) |
publicKey |
string | Public key (present when status is ready) |
createdAt |
string | ISO 8601 creation timestamp |
Sign Raw Data
POST /v1/wallets/{walletId}/sign-raw
Signs arbitrary data using the wallet's MPC key shares. The private key is never assembled -- each share signs independently and the results are combined.
The wallet must be in ready status before signing.
| Field | Type | Required | Description |
|---|---|---|---|
data |
string | Yes | Data to sign as a 0x-prefixed hex string |
EVM Example
curl -X POST https://api.beta.getpara.com/v1/wallets/0a1b2c3d-4e5f-6789-abcd-ef0123456789/sign-raw \
-H "Content-Type: application/json" \
-H "X-API-Key: $PARA_API_KEY" \
-d '{
"data": "0x48656c6c6f20576f726c64"
}'
Solana Example
curl -X POST https://api.beta.getpara.com/v1/wallets/aabbccdd-1122-3344-5566-778899aabbcc/sign-raw \
-H "Content-Type: application/json" \
-H "X-API-Key: $PARA_API_KEY" \
-d '{
"data": "0x01000103b5d..."
}'
Response (200 OK)
{
"signature": "a1b2c3d4e5f6..."
}
The signature is a hex string without the 0x prefix.
List Wallets
Batch-fetch multiple wallets by their IDs. Fetches up to 10 wallets in parallel.
- walletIds: Array of wallet ID strings (max 10)
Key Concepts
Async Wallet Creation
Wallet creation is asynchronous. The POST /v1/wallets call returns immediately with status: "creating". You must poll GET /v1/wallets/{walletId} until status becomes "ready" before you can sign.
# Poll every 1 second until the wallet is ready
WALLET_ID="0a1b2c3d-4e5f-6789-abcd-ef0123456789"
while true; do
RESPONSE=$(curl -s https://api.beta.getpara.com/v1/wallets/$WALLET_ID \
-H "X-API-Key: $PARA_API_KEY")
STATUS=$(echo "$RESPONSE" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
if [ "$STATUS" = "ready" ]; then
echo "$RESPONSE"
break
fi
sleep 1
done
Wallet Uniqueness
Each combination of type + scheme + userIdentifier maps to exactly one wallet. Attempting to create a duplicate returns 409 Conflict with the existing wallet's ID in the response body.
Rate Limits
10 requests/second sustained, 20 burst. The client retries automatically on 429s with exponential backoff.
Error Reference
| Status | Message | Cause | Action |
|---|---|---|---|
| 400 | "type must be one of EVM, SOLANA, COSMOS" |
Invalid or missing request body fields | Check required fields and enum values |
| 401 | "secret api key not provided" |
Missing X-API-Key header |
Add the header with your API key |
| 403 | "invalid secret api key" |
API key is wrong or revoked | Verify at developer.getpara.com |
| 404 | "wallet not found" |
Wallet ID doesn't exist or doesn't belong to your account | Check the wallet ID |
| 409 | "a wallet for this identifier and type already exists" |
Duplicate wallet creation | Use the returned walletId to access the existing wallet |
| 429 | Rate limited | Too many requests | Retry with exponential backoff |
| 500 | "Internal Server Error" |
Server-side issue | Retry after a short delay |
409 Conflict Response
{
"message": "a wallet for this identifier and type already exists",
"walletId": "0a1b2c3d-4e5f-6789-abcd-ef0123456789"
}
Complete Workflow Example
# 1. Create an EVM wallet
RESPONSE=$(curl -s -X POST https://api.beta.getpara.com/v1/wallets \
-H "Content-Type: application/json" \
-H "X-API-Key: $PARA_API_KEY" \
-d '{
"type": "EVM",
"userIdentifier": "[email protected]",
"userIdentifierType": "EMAIL"
}')
WALLET_ID=$(echo "$RESPONSE" | grep -o '"id":"[^"]*"' | cut -d'"' -f4)
echo "Created wallet: $WALLET_ID"
# 2. Poll until ready
while true; do
WALLET=$(curl -s https://api.beta.getpara.com/v1/wallets/$WALLET_ID \
-H "X-API-Key: $PARA_API_KEY")
STATUS=$(echo "$WALLET" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
if [ "$STATUS" = "ready" ]; then
echo "Wallet is ready"
echo "$WALLET"
break
fi
echo "Status: $STATUS -- waiting..."
sleep 1
done
# 3. Sign data
SIGNATURE=$(curl -s -X POST https://api.beta.getpara.com/v1/wallets/$WALLET_ID/sign-raw \
-H "Content-Type: application/json" \
-H "X-API-Key: $PARA_API_KEY" \
-d '{"data": "0x48656c6c6f"}')
echo "Signature: $SIGNATURE"
Node.js REST Client Example
const PARA_API_KEY = process.env.PARA_API_KEY;
const BASE_URL = process.env.PARA_REST_BASE_URL ?? "https://api.beta.getpara.com";
async function callPara<T>(path: string, options: { method?: string; body?: unknown } = {}): Promise<T> {
const { method = "GET", body } = options;
const headers: Record<string, string> = {
"X-API-Key": PARA_API_KEY,
"X-Request-Id": crypto.randomUUID(),
};
if (body) headers["Content-Type"] = "application/json";
const res = await fetch(`${BASE_URL}${path}`, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
const data = await res.json();
if (!res.ok) throw new Error(`Para ${res.status}: ${JSON.stringify(data)}`);
return data as T;
}
// Usage
const wallet = await callPara("/v1/wallets", {
method: "POST",
body: { type: "EVM", userIdentifier: "[email protected]", userIdentifierType: "EMAIL" },
});
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.