> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crycketpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Fulfilling payments

> Listen for payment requests and complete transactions

The fulfiller flow is used when you want to pay — as a customer at a merchant or a friend settling a bill.

## Overview

1. Activate payment mode (biometric gate, integrator-triggered)
2. Listen for a SonicPay audio signal
3. Review the payment details
4. Sign the transaction locally and submit via Crycket

## Step 1: Listen for audio

Once the user activates payment mode, open the microphone and listen for SonicPay audio:

```typescript theme={null}
const received = await sdk.listen();
// received.intentId: string
```

The SDK decodes the near-ultrasonic audio signal and extracts the intent ID.

## Step 2: Handle the received intent

You can use the default UI or build a custom one:

### Default UI

The SDK renders a native bottom sheet with payment details and a confirm button:

```typescript theme={null}
sdk.onIntentReceived(received.intentId, wallet);
// Handles everything — fetch, display, sign, submit
```

### Headless mode

Render your own UI and call `sdk.confirm()` when the user is ready:

```typescript theme={null}
sdk.onIntentReceived(received.intentId, wallet, {
  headless: true,
  onDetails: (intent, summary) => {
    // summary: { amount, token, requestor, ataRentLamports,
    //            estimatedFee, expiresAt }
    // Render your own UI
  },
  onComplete: (intent) => {
    // Payment confirmed
  },
  onError: (error) => {
    // Structured error
  },
});

// When the user taps confirm:
await sdk.confirm();
```

## What happens internally

When the fulfiller confirms:

1. `POST /v1/intents/:id/detected` — signals the requestor SDK that a payer was found
2. `GET /v1/intents/:id` — fetches the full intent details
3. `POST /v1/intents/:id/build` — gets the unsigned transaction blob (includes ATA check on Solana)
4. `wallet.signTransaction(blob)` — the wallet signs locally, private key never leaves the device
5. `POST /v1/intents/:id/submit` — Crycket broadcasts to chain
6. SDK listens via SSE for `confirmed` state

Confirmation typically takes under 5 seconds from submission.

## Retry handling

On Solana, transactions can be dropped if they expire (\~60s). When this happens:

* The intent resets to `created` with `retryRequired: true`
* The SDK surfaces a re-sign prompt to the fulfiller
* A new transaction is built with a fresh blockhash
