Dashboard
๐Ÿฆœ
PARROTDocs
Developer Documentation

Accept USDC on Solana in 5 Minutes

Parrot is a production-ready, non-custodial payment gateway. Payments flow wallet-to-wallet โ€” no smart contracts, no custody, zero deployment.

Quickstart

How it works in your SaaS

Three on-chain steps, zero smart contract deployment.

Step 1

Create Checkout

Your backend creates a payment via API or no-code link in the dashboard.

Step 2

Customer Pays USDC

Customer opens the hosted checkout, connects Phantom / Solflare, and signs an SPL transfer.

Step 3

Webhook & Settle

Our indexer detects on-chain confirmation and fires payment.succeeded to your endpoint.

Core Integration

The Only 3 Things You Need

Just like Stripe โ€” API key, webhook URL, and a hosted checkout page.

1. Secret API Key โ€” sk_test_... / sk_live_...

Authenticate every API call via Authorization: Bearer sk_.... Keys map directly to your business in the database. Test keys target Solana Devnet; live keys settle real USDC on Mainnet. Generate and manage them in Developers โ†’ API Keys.

2. Webhook Endpoint URL

Because on-chain transfers are async, you register an HTTPS endpoint (e.g. https://yoursaas.com/api/webhooks/parrot). Parrot signs every payload with HMAC-SHA256 and delivers it instantly after confirmation. Add yours in Developers โ†’ Webhooks.

3. Hosted Checkout Page

No wallet-connect boilerplate to build. When a payment is created, Parrot generates a unique URL (/checkout/[id] or /pay/[code]). Redirect your customer there โ€” they connect their wallet and sign the transfer. Preview yours from Payment Links.
Architecture Superpower

Zero Smart-Contract Deployment

Unlike EVM chains, you never write or audit a contract. USDC already exists on Solana.

Devnet โ†” Mainnet โ€” how the toggle works

  • โœ“USDC is pre-deployed by Circle. Devnet mint: 4zMMC9srt5...DU. Mainnet mint: EPjFWdd5Au...1v. Parrot hardcodes both โ€” you pick neither.
  • โœ“Instant switch. Use sk_test_ keys โ†’ Devnet RPC + Devnet USDC. Use sk_live_ keys โ†’ Mainnet RPC + real USDC. Flip the Test / Live pill in the top-right of your dashboard.
  • โœ“Direct wallet settlement. Every payment is a native SPL token transfer from the customer's wallet directly into your merchant ATA. No escrow, no custody, no smart-contract attack surface.
Test ModeLive Mode
Key prefixsk_test_...sk_live_...
NetworkSolana DevnetSolana Mainnet
USDC mint4zMMC9srt5...DUEPjFWdd5Au...1v
Real moneyNo โ€” faucet USDCYes โ€” real USDC
How to get USDCfaucet.circle.comAny DEX / CEX
SDK Reference

Node / TypeScript SDK

Install the npm package or call the REST API directly. The SDK handles idempotency, USDC unit conversion, and typed responses.

terminal
npm install @parrotpay/sdk
server.ts โ€” Express / Next.js API Route
import { Parrot } from '@parrotpay/sdk';

// sk_test_... for Devnet ยท sk_live_... for Mainnet
const parrot = new Parrot(process.env.PARROT_SECRET_KEY!);

export async function createCheckoutSession(user: User) {
  const payment = await parrot.payments.create(
    {
      amount: 29.99,               // dollars โ€” auto-converted to 29_990_000 raw units
      customer_email: user.email,
      metadata: { userId: user.id, plan: 'pro_monthly' },
      success_url: 'https://yoursaas.com/app?upgraded=true',
    },
    { idempotencyKey: `order_${user.id}` }  // safe retries
  );

  // Redirect the user to the hosted checkout
  return payment.checkout_url;
}
Webhooks

Verifying Webhook Signatures

Every event is signed with HMAC-SHA256 using your endpoint secret (whsec_...). Replay attacks are rejected if the event is older than 5 minutes.

app/api/webhooks/parrot/route.ts โ€” Next.js App Router
import { verifyWebhook } from '@parrotpay/sdk';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  const rawBody = await req.text();
  const signature = req.headers.get('x-signature') ?? '';

  const isValid = verifyWebhook(rawBody, signature, process.env.PARROT_WEBHOOK_SECRET!);
  if (!isValid) return NextResponse.json({ error: 'bad signature' }, { status: 400 });

  const event = JSON.parse(rawBody);

  if (event.event === 'payment.succeeded') {
    const { metadata, tx_signature } = event.data;
    // โœ… Grant access ยท activate subscription ยท send receipt
    await activateSubscription(metadata.userId, metadata.plan);
  }

  return NextResponse.json({ received: true });
}
Webhook Events
payment.createdA new payment session was created
payment.succeededOn-chain transfer confirmed โ€” grant access now
payment.failedSession expired without a matching transfer
payment.refundedMerchant issued a refund transfer
subscription.createdNew subscription started
subscription.canceledSubscription was canceled
invoice.paidInvoice marked paid after on-chain settle
Feature Access Gating

Subscriptions & Gating

In Web3, wallets can't be auto-charged. Here's the robust pattern used by production SaaS apps.

1

Store period end in your DB

When payment.succeeded fires, set expires_at = now() + 30d for that user.

2

Gate access in middleware

Check expires_at > Date.now(). If expired, redirect to your renewal payment link.

3

Parrot background indexer

Our always-on worker polls the merchant wallet, confirms finality, writes the ledger, and retries webhook delivery with backoff.

๐Ÿฆœ

Ready to go live?

Generate a live API key, flip the toggle, done.

Get API Keys