@signiqo/meridian
v0.2.1
Published
Meridian x402 client and merchant middleware for human and agent payments.
Downloads
238
Maintainers
Readme
@signiqo/meridian
Official Meridian SDK for x402-compatible payments with Signiqo identity, passkey step-up and merchant API keys.
Meridian v1 supports Base USDC, the exact x402 scheme, PAYMENT-REQUIRED, PAYMENT-SIGNATURE, PAYMENT-RESPONSE, and legacy X-PAYMENT verification.
What each team does
Meridian is intentionally split into simple roles:
- Merchant or marketplace: creates a Meridian seller, stores
MERIDIAN_API_KEYon the backend, protects a paid endpoint and serves content only after a validPAYMENT-RESPONSE. - Customer or agent: requests the endpoint, receives HTTP
402, signs the exact USDC authorization with their wallet/Signiqo policy, then retries with the proof. - Meridian: verifies merchant binding, domain, amount, recipient, nonce, expiry, environment, KYB/live gates, replay protection and ledger.
Production integration checklist
Before sharing a live integration with customers:
- Create a Meridian Organization.
- Create a Seller for whoever receives settlement. For marketplaces, use one seller for the marketplace treasury or one seller per vendor if vendors settle separately.
- Create a sandbox Server Key and store it only as a backend environment variable.
- Publish one API Product with exact URL, method, price and docs.
- Protect the endpoint with the SDK and confirm the first unauthenticated request returns HTTP
402. - Paste the
PAYMENT-REQUIREDbody/header into Meridian Test Lab. - Request live only after KYB, seller approval, live Server Key and readiness checks pass.
Marketplace checkout in 5 minutes
Use this pattern when a marketplace sells reports, datasets, APIs, MCP tools or other paid digital resources.
import express from "express";
import { createMeridianMerchant } from "@signiqo/meridian";
const app = express();
const meridian = createMeridianMerchant({
apiKey: process.env.MERIDIAN_API_KEY!,
meridianOrigin: "https://wallet.signiqo.com",
environment: "sandbox",
merchantDomain: "api.marketplace.com",
resource: "https://api.marketplace.com/premium/report",
payTo: "0xYourBaseSettlementAddress",
amount: "0.25",
description: "Premium report",
});
app.get("/premium/report", meridian.express(), (_req, res) => {
res.json({ ok: true, report: "paid content" });
});The SDK validates merchant domain, HTTPS resource URL, Base USDC asset, EVM settlement address, amount, method, nonce and expiry before it emits a payment requirement. Invalid payment proofs return a fresh 402 instead of crashing your route.
First request:
curl -i https://api.marketplace.com/premium/reportExpected result: HTTP 402 with a JSON body and a PAYMENT-REQUIRED header. After the payer gets a valid PAYMENT-RESPONSE, retry:
curl -i https://api.marketplace.com/premium/report \
-H "PAYMENT-RESPONSE: $PAYMENT_RESPONSE"Expected result: HTTP 200 with the paid content.
Next.js, Hono or Cloudflare Workers
import { createMeridianMerchant } from "@signiqo/meridian";
const meridian = createMeridianMerchant({
apiKey: process.env.MERIDIAN_API_KEY!,
merchantDomain: "api.your-company.com",
resource: "https://api.your-company.com/v1/data",
payTo: "0xYourBaseSettlementAddress",
amount: "0.10",
description: "Data lookup",
});
export const GET = meridian.protectFetch(async () => {
return Response.json({ data: "paid response" });
});Pay with Meridian button
For human checkout, generate the payment URL on your server and render it as a button. Keep the API key server-side.
const url = meridian.payUrl("https://marketplace.com/checkout/complete");<a href="{url}">Pay with Meridian</a>The hosted Meridian flow handles wallet connection, policy checks and biometric step-up when required.
Payer or agent flow
This is the low-level flow for wallets, agent runtimes or server-side test harnesses. In production, a browser should not receive merchant API keys. The merchant middleware can settle a signed payment when the retry includes both the original PAYMENT-REQUIRED and the new PAYMENT-SIGNATURE.
import {
createPaymentSignatureHeader,
createSignedPaymentPayload,
parsePaymentRequired,
} from "@signiqo/meridian";
const response = await fetch("https://api.marketplace.com/premium/report");
const paymentRequired = await parsePaymentRequired(response);
const signed = await createSignedPaymentPayload({
requirement: paymentRequired,
payer: "0xPayerWallet",
signTypedData: (typedData) =>
walletClient.signTypedData({
account: "0xPayerWallet",
domain: typedData.domain,
types: typedData.types,
primaryType: typedData.primaryType,
message: typedData.message,
}),
});
await fetch("https://api.marketplace.com/premium/report", {
headers: {
"PAYMENT-REQUIRED": response.headers.get("PAYMENT-REQUIRED")!,
"PAYMENT-SIGNATURE": createPaymentSignatureHeader(signed.paymentPayload),
},
});The merchant backend calls Meridian settlement with its server API key, attaches PAYMENT-RESPONSE to the successful response, and unlocks the resource.
Server-side settlement helper
Use this only on trusted servers because it requires a Meridian API key.
import { settleSignedPayment } from "@signiqo/meridian";
const result = await settleSignedPayment({
apiKey: process.env.MERIDIAN_API_KEY!,
requirement: paymentRequired,
payer: "0xPayerWallet",
merchantDomain: "api.marketplace.com",
signTypedData,
});
console.log(result.settlement);Sandbox vs live
Use sandbox while integrating. Sandbox keys prove the HTTP contract and policy surface but never look like live mainnet settlement.
Use live only after:
- Domain is verified.
- KYB is approved.
- Settlement address is validated.
- Merchant is live-enabled.
- Live API key is active and scoped.
- Meridian readiness checks pass.
Live API keys are issued only after approval. Keep every API key on the server, rotate regularly and never expose it in browser JavaScript, mobile apps, public repos or client-side environment variables.
Local third-party smoke test
This demo behaves like an external merchant API. It protects /premium/report, returns 402 PAYMENT-REQUIRED, and verifies PAYMENT-RESPONSE with Meridian before serving paid content.
npm run build
MERIDIAN_ORIGIN=https://wallet.signiqo.com \
MERIDIAN_API_KEY=sk_siq_sandbox_or_live_key \
MERCHANT_DOMAIN=localhost \
MERCHANT_SETTLEMENT_ADDRESS=0xYourBaseSettlementAddress \
node examples/node-http-merchant-demo.mjsRequest without payment:
curl -i http://localhost:8787/premium/reportRetry with proof:
curl -i http://localhost:8787/premium/report \
-H "PAYMENT-RESPONSE: $PAYMENT_RESPONSE"Security defaults
- API keys are server-only.
- Requirements expire quickly.
- Payment signatures are bound to amount, token, recipient, resource, method, nonce and expiry.
- Merchant verification checks domain, amount and resource URL.
- Live settlement is gated by KYB, environment, merchant status and readiness switches.
- Agents never receive raw
tx:send; they operate through Meridian policies. - Resource and return URLs must be HTTPS, except localhost for development.
- Resource hostnames must match the configured merchant domain or a subdomain.
- Headers are size-limited to reduce abuse and memory pressure.
- Payment requirements are sent with
Cache-Control: no-storebecause they contain single-use nonces. - Unsupported methods, non-Base assets, malformed EVM addresses and expired requirements are rejected before settlement.
