Rezva

Free API and Test Merchant

A complete, approval-free path for integrating identifier resolution into a prototype wallet. You will generate a key, read the shared Test Merchant QR, resolve it, and send a real Base Sepolia USDC payment from your wallet.

Requirements

  • A Rezva dashboard account at /dashboard.
  • An active Free API key from /dashboard/free-api.
  • A wallet that can send Base Sepolia USDC.
  • A configured Rezva resolver URL. Use the URL in the QR payload.

The Test Merchant is a protocol demo merchant. It is not a real merchant and must only receive testnet funds.

1. Get a Free API key

Open the Free API dashboard and select Generate key. The complete plaintext key is shown only at that moment. Store it in a server-side environment variable; do not commit it or put it in a browser bundle.

# .env.local (never commit this file)
REZVA_FREE_API_KEY=rzva_free_…
REZVA_API_BASE_URL=https://api.example.com

Regeneration revokes the previous key. If a key is exposed, revoke it immediately from the dashboard and generate a replacement.

2. Read the Test Merchant QR

Open Test Merchant in the Free API dashboard. The same persistent merchant identifier, wallet, and QR payload are used by every developer in the environment. A QR scanner should parse the JSON rather than treating the entire QR text as an address.

{
  "resolver_url": "https://api.example.com/v1/resolve",
  "type": "custom",
  "value": "rezva-test-merchant"
}

Save resolver_url, type, and value. The wallet sends only type and value to the resolver.

3. Resolve the identifier

Make an authenticated POST request to the QR’s resolver URL. The key is valid for this resolver operation only.

TypeScript

const response = await fetch(
  "https://api.example.com/v1/resolve",
  {
    method: "POST",
    headers: {
      "content-type": "application/json",
      authorization: `Bearer ${process.env.REZVA_FREE_API_KEY}`,
    },
    body: JSON.stringify({
      type: "custom",
      value: "rezva-test-merchant",
    }),
  },
);

if (!response.ok) {
  throw new Error(`Resolve failed: ${response.status} ${await response.text()}`);
}

const resolved = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.example.com/v1/resolve",
    headers={
        "content-type": "application/json",
        "authorization": f"Bearer {os.environ['REZVA_FREE_API_KEY']}",
    },
    json={"type": "custom", "value": "rezva-test-merchant"},
    timeout=10,
)
response.raise_for_status()
resolved = response.json()

A successful response includes lifecycle state and one or more payment options. The resolver does not create, sign, broadcast, or confirm the blockchain transaction.

{
  "protocol_version": "1",
  "status": "active",
  "payment_ready": true,
  "identifier": {
    "type": "custom",
    "value": "rezva-test-merchant",
    "normalized_value": "rezva-test-merchant"
  },
  "payment_options": [
    {
      "chain": "base",
      "asset": "USDC",
      "address": "0xMerchantWallet",
      "token_contract": "0xBaseSepoliaUsdc",
      "network_identifier": "eip155:84532",
      "payment_ready": true
    }
  ]
}

4. Choose the payment option safely

Never select the first array item blindly. Filter by the chain and asset your wallet supports, then require both readiness flags.

const option = resolved.payment_options.find(
  (candidate) =>
    candidate.chain === "base" &&
    candidate.asset === "USDC" &&
    candidate.network_identifier === "eip155:84532" &&
    candidate.payment_ready === true,
);

if (resolved.status !== "active" || !resolved.payment_ready || !option) {
  throw new Error("The destination is not ready for Base Sepolia USDC payment");
}

// Show these values and get explicit user confirmation:
console.log({
  chain: option.chain,
  network: option.network_identifier,
  asset: option.asset,
  tokenContract: option.token_contract,
  recipient: option.address,
});
  • address is the recipient for the token transfer.
  • token_contract identifies the USDC contract to call.
  • network_identifier eip155:84532 is Base Sepolia.
  • Respect minimum_amount, maximum_amount, fixed_amount, and expiration when present.

5. Execute and verify the payment

  1. Switch the wallet to Base Sepolia (chain ID 84532).
  2. Show the token contract and recipient to the user.
  3. Ask for the amount and explicit confirmation.
  4. Use the wallet’s own signer to call the USDC transfer function.
  5. Wait for the transaction receipt and require a successful status.
  6. Verify the recipient and amount in the USDC Transfer event.
// The wallet owns this step. Rezva never receives private keys.
const txHash = await wallet.sendUsdc({
  chainId: 84532,
  token: option.token_contract,
  recipient: option.address,
  amount: "0.01",
});

const receipt = await wallet.waitForTransaction(txHash);
if (receipt.status !== "success") {
  throw new Error("Base Sepolia transaction failed");
}

For the demo flow, verify the real transaction independently at https://sepolia.basescan.org/ by searching the transaction hash or the shared merchant wallet. The dashboard’s Detected payments table also shows the confirmed transaction after its ledger scan.

Errors and limits

  • 401 — missing, invalid, revoked, or misplaced key.
  • 404 — the typed identifier was not found.
  • 400 — unsupported type or invalid identifier value.
  • 429 — the Free API limit was reached; honor Retry-After.

Each Free API key allows 10 resolver requests per minute and 100 resolver requests per UTC day. It cannot register, update, suspend, remove identifiers, manage namespaces, or access operator data.

if (response.status === 429) {
  const retryAfter = Number(response.headers.get("retry-after") ?? "60");
  await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
}

Continue with the API Reference for field definitions, or use the OpenAPI specification to generate a client.

Open Free API testing