LOOMAL
SDK / API ReferenceSellers

Register Endpoint

Register a paid URL with optional webhook

Scope: payments:accept

Registers (or updates) a paid endpoint. Registration is optional — payments still record without it. What you get by registering:

  • A webhook fired on every successful payment to that URL
  • Per-endpoint call count + revenue counters in the dashboard
  • An auditable price + description displayed alongside payments

Admin endpoint — currently only available via REST or the Console UI.

The easiest way to register an endpoint with a webhook secret is console.loomal.ai → your project → Pay → Endpoints → Add endpoint. Loomal generates a whsec_… HMAC secret and shows it once. Use this REST endpoint when you need to provision endpoints from automation.

Request

curl -X PUT https://api.loomal.ai/v0/sellers/endpoints \
  -H "Authorization: Bearer loid-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "urlPattern": "https://your-api.com/search",
    "priceUsdc": "0.05",
    "network": "base",
    "webhookUrl": "https://your-api.com/webhooks/payment",
    "webhookSecret": "a-strong-shared-secret-16-chars+"
  }'

Body

FieldTypeRequiredDescription
urlPatternstringYesFull HTTPS URL of the paid endpoint. Must be public (HTTPS, no private IPs).
priceUsdcstringYesDecimal USDC, up to 6 fractional digits
networkstringNo"base" (Base mainnet, default and only supported value)
webhookUrlstringNoHTTPS URL — Loomal POSTs payment receipts here. SSRF-validated against private IPs at registration AND each delivery.
webhookSecretstringNoMin 16 chars. Used to HMAC-sign webhook bodies. Stored encrypted. Omit and use the Console UI for a Loomal-generated secret.

Response — 201 Created

{
  "endpointId": "se_abc123",
  "urlPattern": "https://your-api.com/search",
  "priceUsdc": "0.05",
  "network": "base",
  "webhookUrl": "https://your-api.com/webhooks/payment",
  "active": true,
  "createdAt": "2026-04-28T12:00:00Z"
}

Webhook payload

When a payment settles, Loomal POSTs to your webhookUrl:

POST /webhooks/payment HTTP/1.1
Content-Type: application/json
X-Loomal-Event: payment.received
X-Loomal-Signature: sha256=<hex>
X-Loomal-Idempotency-Key: <uuid>

{
  "type": "payment.received",
  "data": {
    "body": { /* canonical receipt body — see Get Payment */ },
    "signature": "<base64 Ed25519>",
    "publicKeyHex": "<64-char hex>",
    "alg": "Ed25519"
  },
  "idempotencyKey": "<uuid>"
}

Verify the signature with the SDK helper:

import { verifyWebhook } from "@loomal/sdk/webhook";

const ok = await verifyWebhook(
  rawBody,
  req.header("x-loomal-signature"),
  process.env.LOOMAL_WEBHOOK_SECRET!,
);
if (!ok) return res.status(400).send("invalid signature");
from loomal.webhook import verify_webhook

ok = verify_webhook(
    raw_body,
    request.headers.get("x-loomal-signature"),
    os.environ["LOOMAL_WEBHOOK_SECRET"],
)

Loomal retries failed deliveries with backoff (1s, 4s, 16s, 64s, 300s) up to 5 times. 4xx responses abort the chain. De-dupe on X-Loomal-Idempotency-Key.

Errors

StatuserrorCause
400bad_requesturlPattern missing/invalid, priceUsdc malformed or <= 0
400bad_requestwebhookUrl rejected — must be HTTPS and resolve to a public IP
401unauthorizedMissing or invalid Authorization
403forbiddenAPI key lacks payments:accept scope
409conflictEndpoint already exists for this Identity + URL combination
503feature_disabledPayments not enabled on this Loomal instance

Next

GET /v0/sellers/endpoints — list registered endpoints with their counters.

On this page