Quickstart

Go from zero to sending emails and creating crypto invoices in under 5 minutes.

1

Create your account

Sign up at clawstack.polsia.app/login. You'll get an API key automatically — copy it from the dashboard.

2

Send your first email

Hit the email endpoint with your API key. That's it — no SMTP config, no domain verification.

3

Create a crypto invoice

Accept BTC, ETH, USDC, and 50+ tokens. One API call returns a hosted payment page.

Send your first email

curl -X POST https://clawstack.polsia.app/api/email/send \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "to": "hello@example.com",
    "subject": "Hello from ClawStack",
    "body": "Your first email is live!"
  }'
const response = await fetch("https://clawstack.polsia.app/api/email/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": "YOUR_API_KEY"
  },
  body: JSON.stringify({
    to: "hello@example.com",
    subject: "Hello from ClawStack",
    body: "Your first email is live!"
  })
});

const data = await response.json();
console.log(data);
// { success: true, data: { message_id: "abc-123", ... } }
import requests

response = requests.post(
    "https://clawstack.polsia.app/api/email/send",
    headers={
        "Content-Type": "application/json",
        "x-api-key": "YOUR_API_KEY"
    },
    json={
        "to": "hello@example.com",
        "subject": "Hello from ClawStack",
        "body": "Your first email is live!"
    }
)

data = response.json()
print(data)
# {"success": True, "data": {"message_id": "abc-123", ...}}

Create your first invoice

curl -X POST https://clawstack.polsia.app/api/payments/create-invoice \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "amount": 49.99,
    "currency": "USD",
    "order_id": "order_001",
    "order_description": "Pro Plan — Monthly"
  }'
const response = await fetch("https://clawstack.polsia.app/api/payments/create-invoice", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": "YOUR_API_KEY"
  },
  body: JSON.stringify({
    amount: 49.99,
    currency: "USD",
    order_id: "order_001",
    order_description: "Pro Plan — Monthly"
  })
});

const data = await response.json();
console.log(data.data.invoice_url);
// Redirect user to this URL to complete payment
import requests

response = requests.post(
    "https://clawstack.polsia.app/api/payments/create-invoice",
    headers={
        "Content-Type": "application/json",
        "x-api-key": "YOUR_API_KEY"
    },
    json={
        "amount": 49.99,
        "currency": "USD",
        "order_id": "order_001",
        "order_description": "Pro Plan — Monthly"
    }
)

data = response.json()
print(data["data"]["invoice_url"])
# Redirect user to this URL to complete payment
Sandbox mode: ClawStack is currently in sandbox. Emails and invoices work end-to-end, but no real charges occur. Perfect for building and testing your integration.

Authentication

Every API request requires your key in the x-api-key header.

x-api-key: cs_live_a1b2c3d4e5f6...

Get your API key from the dashboard after signing up. You can create up to 5 keys per account — useful for separating dev/staging/prod environments.

Keep your key secret. Never expose it in client-side code or public repos. If compromised, deactivate it immediately from your dashboard and generate a new one.

Key format

All keys start with cs_live_ followed by 48 hex characters. If your key doesn't match this format, something's wrong.

Test your key

# A valid key returns 200. Invalid returns 401.
curl -s -o /dev/null -w "%{http_code}" \
  -X POST https://clawstack.polsia.app/api/email/send \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{"to":"test@test.com","subject":"ping","body":"pong"}'
// Quick auth check — send a test email
const res = await fetch("https://clawstack.polsia.app/api/email/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": "YOUR_API_KEY"
  },
  body: JSON.stringify({
    to: "test@test.com",
    subject: "ping",
    body: "pong"
  })
});

console.log(res.status); // 200 = valid, 401 = bad key
# Quick auth check
import requests

res = requests.post(
    "https://clawstack.polsia.app/api/email/send",
    headers={
        "Content-Type": "application/json",
        "x-api-key": "YOUR_API_KEY"
    },
    json={"to": "test@test.com", "subject": "ping", "body": "pong"}
)

print(res.status_code)  # 200 = valid, 401 = bad key

Send Email

Send transactional emails through Postmark-backed infrastructure. High deliverability, zero SMTP setup.

POST /api/email/send

Send a transactional email to one or more recipients. Supports plain text and HTML content.

Request body

ParameterTypeDescription
to required string | string[] Recipient email(s). Single address or array.
subject required string Email subject line
body string Plain text body. Provide body and/or html_body.
html_body string HTML body for rich formatting
from_name string Sender display name (e.g. "MyApp")
tag string Tag for analytics and filtering

Examples

# Send a plain text email
curl -X POST https://clawstack.polsia.app/api/email/send \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "to": "user@example.com",
    "subject": "Your receipt",
    "body": "Thanks for your purchase! Order #12345."
  }'

# Send an HTML email to multiple recipients
curl -X POST https://clawstack.polsia.app/api/email/send \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "to": ["user1@example.com", "user2@example.com"],
    "subject": "Weekly Report",
    "html_body": "<h1>Weekly Report</h1><p>Here are your metrics...</p>",
    "from_name": "Analytics Bot",
    "tag": "reports"
  }'
const CLAWSTACK_KEY = process.env.CLAWSTACK_API_KEY;
const BASE_URL = "https://clawstack.polsia.app";

// Helper function
async function sendEmail({ to, subject, body, htmlBody, fromName, tag }) {
  const res = await fetch(`${BASE_URL}/api/email/send`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": CLAWSTACK_KEY
    },
    body: JSON.stringify({
      to,
      subject,
      ...(body && { body }),
      ...(htmlBody && { html_body: htmlBody }),
      ...(fromName && { from_name: fromName }),
      ...(tag && { tag })
    })
  });
  return res.json();
}

// Plain text email
const result = await sendEmail({
  to: "user@example.com",
  subject: "Your receipt",
  body: "Thanks for your purchase! Order #12345."
});
console.log(result.data.message_id);

// HTML email to multiple recipients
const batch = await sendEmail({
  to: ["user1@example.com", "user2@example.com"],
  subject: "Weekly Report",
  htmlBody: "<h1>Weekly Report</h1><p>Your metrics...</p>",
  fromName: "Analytics Bot",
  tag: "reports"
});
import os
import requests

CLAWSTACK_KEY = os.environ["CLAWSTACK_API_KEY"]
BASE_URL = "https://clawstack.polsia.app"

def send_email(to, subject, body=None, html_body=None, from_name=None, tag=None):
    payload = {"to": to, "subject": subject}
    if body:
        payload["body"] = body
    if html_body:
        payload["html_body"] = html_body
    if from_name:
        payload["from_name"] = from_name
    if tag:
        payload["tag"] = tag

    response = requests.post(
        f"{BASE_URL}/api/email/send",
        headers={
            "Content-Type": "application/json",
            "x-api-key": CLAWSTACK_KEY
        },
        json=payload
    )
    return response.json()

# Plain text email
result = send_email(
    to="user@example.com",
    subject="Your receipt",
    body="Thanks for your purchase! Order #12345."
)
print(result["data"]["message_id"])

# HTML email to multiple recipients
batch = send_email(
    to=["user1@example.com", "user2@example.com"],
    subject="Weekly Report",
    html_body="<h1>Weekly Report</h1><p>Your metrics...</p>",
    from_name="Analytics Bot",
    tag="reports"
)

Response

{
  "success": true,
  "data": {
    "message_id": "abc-123-def-456",
    "submitted_at": "2026-03-18T12:00:00Z",
    "to": ["user@example.com"]
  }
}
Cost: $0.001 per recipient (0.1 cents). Sending to 3 recipients costs $0.003 total.

Create Invoice

Create crypto payment invoices that accept BTC, ETH, USDC, and 50+ tokens via NOWPayments.

POST /api/payments/create-invoice

Create a hosted payment page. Redirect your user to the returned invoice_url to collect payment.

Request body

ParameterTypeDescription
amount required number Invoice amount (e.g. 49.99). Must be > 0.
currency required string Price currency: USD, EUR, BTC, etc.
pay_currency string Specific crypto to accept (BTC, ETH, USDC). Omit for multi-currency checkout.
order_id string Your internal order/reference ID
order_description string Description shown on the payment page
success_url string Redirect after successful payment
cancel_url string Redirect if user cancels

Examples

# Create a USD invoice, payable in any crypto
curl -X POST https://clawstack.polsia.app/api/payments/create-invoice \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "amount": 49.99,
    "currency": "USD",
    "order_id": "order_abc",
    "order_description": "Pro Plan — Monthly",
    "success_url": "https://myapp.com/thanks",
    "cancel_url": "https://myapp.com/pricing"
  }'

# Accept only USDC payments
curl -X POST https://clawstack.polsia.app/api/payments/create-invoice \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "amount": 100,
    "currency": "USD",
    "pay_currency": "USDC"
  }'
const CLAWSTACK_KEY = process.env.CLAWSTACK_API_KEY;
const BASE_URL = "https://clawstack.polsia.app";

async function createInvoice({ amount, currency, payCurrency, orderId, description, successUrl, cancelUrl }) {
  const res = await fetch(`${BASE_URL}/api/payments/create-invoice`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": CLAWSTACK_KEY
    },
    body: JSON.stringify({
      amount,
      currency,
      ...(payCurrency && { pay_currency: payCurrency }),
      ...(orderId && { order_id: orderId }),
      ...(description && { order_description: description }),
      ...(successUrl && { success_url: successUrl }),
      ...(cancelUrl && { cancel_url: cancelUrl })
    })
  });
  return res.json();
}

// Create invoice and redirect user
const invoice = await createInvoice({
  amount: 49.99,
  currency: "USD",
  orderId: "order_abc",
  description: "Pro Plan — Monthly",
  successUrl: "https://myapp.com/thanks",
  cancelUrl: "https://myapp.com/pricing"
});

// Redirect user to payment page
console.log(invoice.data.invoice_url);
// "https://nowpayments.io/payment/..."
import os
import requests

CLAWSTACK_KEY = os.environ["CLAWSTACK_API_KEY"]
BASE_URL = "https://clawstack.polsia.app"

def create_invoice(amount, currency, pay_currency=None, order_id=None,
                   description=None, success_url=None, cancel_url=None):
    payload = {"amount": amount, "currency": currency}
    if pay_currency:
        payload["pay_currency"] = pay_currency
    if order_id:
        payload["order_id"] = order_id
    if description:
        payload["order_description"] = description
    if success_url:
        payload["success_url"] = success_url
    if cancel_url:
        payload["cancel_url"] = cancel_url

    response = requests.post(
        f"{BASE_URL}/api/payments/create-invoice",
        headers={
            "Content-Type": "application/json",
            "x-api-key": CLAWSTACK_KEY
        },
        json=payload
    )
    return response.json()

# Create invoice and redirect user
invoice = create_invoice(
    amount=49.99,
    currency="USD",
    order_id="order_abc",
    description="Pro Plan — Monthly",
    success_url="https://myapp.com/thanks",
    cancel_url="https://myapp.com/pricing"
)

print(invoice["data"]["invoice_url"])
# "https://nowpayments.io/payment/..."

Response

{
  "success": true,
  "data": {
    "invoice_id": "inv_abc123",
    "invoice_url": "https://nowpayments.io/payment/...",
    "status": "pending",
    "price_amount": 49.99,
    "price_currency": "USD",
    "created_at": "2026-03-18T12:00:00Z"
  }
}
Cost: $0.005 per invoice created (0.5 cents). You're only charged when the invoice is created, not when it's paid.

Check Invoice Status

Poll the status of a payment invoice to confirm payment completion.

GET /api/payments/invoice/:id

Returns the current status of an invoice. Use this to verify payment before fulfilling orders.

Statuses: pendingconfirmingconfirmedfinished | expired

curl https://clawstack.polsia.app/api/payments/invoice/inv_abc123 \
  -H "x-api-key: YOUR_API_KEY"
async function checkInvoice(invoiceId) {
  const res = await fetch(
    `https://clawstack.polsia.app/api/payments/invoice/${invoiceId}`,
    { headers: { "x-api-key": process.env.CLAWSTACK_API_KEY } }
  );
  return res.json();
}

const status = await checkInvoice("inv_abc123");

if (status.data.status === "finished") {
  console.log("Payment confirmed! Fulfill the order.");
} else {
  console.log(`Status: ${status.data.status}`);
}
import os
import requests

def check_invoice(invoice_id):
    response = requests.get(
        f"https://clawstack.polsia.app/api/payments/invoice/{invoice_id}",
        headers={"x-api-key": os.environ["CLAWSTACK_API_KEY"]}
    )
    return response.json()

status = check_invoice("inv_abc123")

if status["data"]["status"] == "finished":
    print("Payment confirmed! Fulfill the order.")
else:
    print(f"Status: {status['data']['status']}")

Response

{
  "success": true,
  "data": {
    "invoice_id": "inv_abc123",
    "status": "finished",
    "price_amount": 49.99,
    "price_currency": "USD",
    "invoice_url": "https://nowpayments.io/payment/..."
  }
}

AI Agent Integration

Wire ClawStack into your AI agent so it can send emails and collect payments autonomously.

Node.js agent with tool functions

Define ClawStack as tool functions your AI agent can call. Works with OpenAI, Anthropic, LangChain, or any framework that supports function calling.

// ClawStack tool definitions for your AI agent
const CLAWSTACK_KEY = process.env.CLAWSTACK_API_KEY;
const BASE = "https://clawstack.polsia.app";

const clawstackTools = {
  send_email: {
    description: "Send a transactional email to a user",
    parameters: {
      to: { type: "string", description: "Recipient email" },
      subject: { type: "string", description: "Subject line" },
      body: { type: "string", description: "Email body (plain text or HTML)" }
    },
    execute: async ({ to, subject, body }) => {
      const res = await fetch(`${BASE}/api/email/send`, {
        method: "POST",
        headers: { "Content-Type": "application/json", "x-api-key": CLAWSTACK_KEY },
        body: JSON.stringify({ to, subject, html_body: body })
      });
      return res.json();
    }
  },

  create_invoice: {
    description: "Create a crypto payment invoice",
    parameters: {
      amount: { type: "number", description: "Amount in USD" },
      order_id: { type: "string", description: "Your order reference" },
      description: { type: "string", description: "What the payment is for" }
    },
    execute: async ({ amount, order_id, description }) => {
      const res = await fetch(`${BASE}/api/payments/create-invoice`, {
        method: "POST",
        headers: { "Content-Type": "application/json", "x-api-key": CLAWSTACK_KEY },
        body: JSON.stringify({
          amount,
          currency: "USD",
          order_id,
          order_description: description
        })
      });
      return res.json();
    }
  }
};

// Usage with OpenAI function calling
const tools = Object.entries(clawstackTools).map(([name, tool]) => ({
  type: "function",
  function: {
    name,
    description: tool.description,
    parameters: {
      type: "object",
      properties: tool.parameters,
      required: Object.keys(tool.parameters)
    }
  }
}));

// When the model calls a tool:
async function handleToolCall(name, args) {
  return clawstackTools[name].execute(args);
}
import os
import requests
import json

CLAWSTACK_KEY = os.environ["CLAWSTACK_API_KEY"]
BASE = "https://clawstack.polsia.app"
HEADERS = {"Content-Type": "application/json", "x-api-key": CLAWSTACK_KEY}

# Tool functions your agent can call
def send_email(to: str, subject: str, body: str) -> dict:
    """Send a transactional email to a user."""
    return requests.post(f"{BASE}/api/email/send", headers=HEADERS, json={
        "to": to, "subject": subject, "html_body": body
    }).json()

def create_invoice(amount: float, order_id: str, description: str) -> dict:
    """Create a crypto payment invoice."""
    return requests.post(f"{BASE}/api/payments/create-invoice", headers=HEADERS, json={
        "amount": amount, "currency": "USD",
        "order_id": order_id, "order_description": description
    }).json()

# OpenAI function calling schema
tools = [
    {
        "type": "function",
        "function": {
            "name": "send_email",
            "description": "Send a transactional email to a user",
            "parameters": {
                "type": "object",
                "properties": {
                    "to": {"type": "string", "description": "Recipient email"},
                    "subject": {"type": "string", "description": "Subject line"},
                    "body": {"type": "string", "description": "Email body (HTML)"}
                },
                "required": ["to", "subject", "body"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "create_invoice",
            "description": "Create a crypto payment invoice",
            "parameters": {
                "type": "object",
                "properties": {
                    "amount": {"type": "number", "description": "Amount in USD"},
                    "order_id": {"type": "string", "description": "Order reference"},
                    "description": {"type": "string", "description": "What the payment is for"}
                },
                "required": ["amount", "order_id", "description"]
            }
        }
    }
]

# Handle tool calls from the model
TOOL_MAP = {"send_email": send_email, "create_invoice": create_invoice}

def handle_tool_call(name: str, args: dict) -> dict:
    return TOOL_MAP[name](**args)

Full agent example: invoice + receipt email

A common pattern — create an invoice, then email the payment link to the customer.

const CLAWSTACK_KEY = process.env.CLAWSTACK_API_KEY;
const BASE = "https://clawstack.polsia.app";
const headers = { "Content-Type": "application/json", "x-api-key": CLAWSTACK_KEY };

async function chargeCustomer(email, amount, orderId, productName) {
  // 1. Create the invoice
  const invoiceRes = await fetch(`${BASE}/api/payments/create-invoice`, {
    method: "POST", headers,
    body: JSON.stringify({
      amount,
      currency: "USD",
      order_id: orderId,
      order_description: productName,
      success_url: `https://myapp.com/orders/${orderId}/thanks`
    })
  });
  const invoice = await invoiceRes.json();

  if (!invoice.success) throw new Error(invoice.error);

  // 2. Email the payment link
  const emailRes = await fetch(`${BASE}/api/email/send`, {
    method: "POST", headers,
    body: JSON.stringify({
      to: email,
      subject: `Invoice for ${productName}`,
      html_body: `
        <h2>Your invoice is ready</h2>
        <p>Amount: $${amount} USD</p>
        <p><a href="${invoice.data.invoice_url}">Pay Now</a></p>
      `,
      from_name: "MyApp Billing",
      tag: "invoices"
    })
  });

  return { invoice: invoice.data, email: (await emailRes.json()).data };
}

// Usage
await chargeCustomer("buyer@example.com", 99, "ord_789", "Annual Plan");
import os
import requests

CLAWSTACK_KEY = os.environ["CLAWSTACK_API_KEY"]
BASE = "https://clawstack.polsia.app"
HEADERS = {"Content-Type": "application/json", "x-api-key": CLAWSTACK_KEY}

def charge_customer(email, amount, order_id, product_name):
    # 1. Create the invoice
    invoice_res = requests.post(f"{BASE}/api/payments/create-invoice", headers=HEADERS, json={
        "amount": amount,
        "currency": "USD",
        "order_id": order_id,
        "order_description": product_name,
        "success_url": f"https://myapp.com/orders/{order_id}/thanks"
    }).json()

    if not invoice_res["success"]:
        raise Exception(invoice_res["error"])

    payment_url = invoice_res["data"]["invoice_url"]

    # 2. Email the payment link
    email_res = requests.post(f"{BASE}/api/email/send", headers=HEADERS, json={
        "to": email,
        "subject": f"Invoice for {product_name}",
        "html_body": f"""
            <h2>Your invoice is ready</h2>
            <p>Amount: ${amount} USD</p>
            <p><a href="{payment_url}">Pay Now</a></p>
        """,
        "from_name": "MyApp Billing",
        "tag": "invoices"
    }).json()

    return {"invoice": invoice_res["data"], "email": email_res["data"]}

# Usage
result = charge_customer("buyer@example.com", 99, "ord_789", "Annual Plan")
print(result["invoice"]["invoice_url"])

Error Handling

All errors return a consistent JSON shape. Check success first, then handle the HTTP status code.

// Every error response looks like this:
{
  "success": false,
  "error": "Description of what went wrong"
}

// Rate limit errors include extra fields:
{
  "success": false,
  "error": "Rate limit exceeded",
  "limit": 60,
  "retry_after_seconds": 60
}

Status codes

200Success
400Bad request — missing or invalid parameters
401Unauthorized — missing or invalid API key
403Forbidden — API key deactivated
429Rate limit exceeded — wait and retry
502Upstream error — provider issue, retry in a few seconds

Handling errors in code

async function clawstackRequest(endpoint, body) {
  const res = await fetch(`https://clawstack.polsia.app${endpoint}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": process.env.CLAWSTACK_API_KEY
    },
    body: JSON.stringify(body)
  });

  const data = await res.json();

  if (!data.success) {
    if (res.status === 429) {
      // Rate limited — wait and retry
      const wait = (data.retry_after_seconds || 60) * 1000;
      await new Promise(r => setTimeout(r, wait));
      return clawstackRequest(endpoint, body); // retry once
    }
    throw new Error(`ClawStack ${res.status}: ${data.error}`);
  }

  return data;
}
import time
import requests
import os

def clawstack_request(endpoint, body):
    res = requests.post(
        f"https://clawstack.polsia.app{endpoint}",
        headers={
            "Content-Type": "application/json",
            "x-api-key": os.environ["CLAWSTACK_API_KEY"]
        },
        json=body
    )
    data = res.json()

    if not data["success"]:
        if res.status_code == 429:
            # Rate limited — wait and retry
            wait = data.get("retry_after_seconds", 60)
            time.sleep(wait)
            return clawstack_request(endpoint, body)  # retry once
        raise Exception(f"ClawStack {res.status_code}: {data['error']}")

    return data

Rate Limits

ClawStack enforces per-key rate limiting to keep the platform stable.

LimitValueDetails
Requests 60/min Per API key. Shared across all endpoints.
Email recipients No limit* Each recipient in a batch counts as 1 request toward rate limit.
API keys 5 per account Create separate keys for dev/staging/prod.
Need higher limits? Contact us and we'll bump your rate limit. We're in sandbox — limits are generous.