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

# Paid Reads

> Pay-per-query monetization for read operations

OnDB supports paid read operations. When a query requires payment, the SDK throws `PaymentRequiredError` containing a payment quote. You then pay and re-query using `executeWithPayment()`.

## How It Works

```
1. App executes query via queryBuilder().execute()
       |
2. Server determines payment is required
       |
3. SDK throws PaymentRequiredError with quote
       |
4. App processes payment using quote details
       |
5. App re-queries with executeWithPayment(quoteId, txHash)
       |
6. Server verifies payment and returns data
```

## Basic Example

```typescript theme={null}
import { createClient, PaymentRequiredError } from '@ondb/sdk';

try {
  const result = await client.queryBuilder()
    .collection('premium_data')
    .selectAll()
    .execute();

  // Query succeeded without payment
  console.log('Records:', result.records);
} catch (error) {
  if (error instanceof PaymentRequiredError) {
    const paymentInfo = error.paymentRequired;

    console.log('Payment required!');
    console.log('Error:', paymentInfo.error);
    console.log('Payment options:', paymentInfo.accepts.length);
    // Each option in accepts[] contains: network, maxAmountRequired, payTo, tokenSymbol, etc.
  }
}
```

## Pay and Re-Query

After catching `PaymentRequiredError`, process the payment and use `executeWithPayment()` to retry:

```typescript theme={null}
import { createClient, PaymentRequiredError } from '@ondb/sdk';

async function queryWithPayment() {
  const query = client.queryBuilder()
    .collection('premium_data')
    .whereField('category').equals('exclusive')
    .selectFields(['title', 'content', 'price'])
    .limit(10);

  try {
    // Try the query first
    const result = await query.execute();
    return result.records;
  } catch (error) {
    if (error instanceof PaymentRequiredError) {
      const requirement = error.paymentRequired.accepts[0];
      console.log(`Payment required: ${requirement.maxAmountRequired} ${requirement.tokenSymbol}`);

      // Process payment using the requirement details
      const txHash = await processPayment(requirement);

      // Re-query with payment proof
      const paidResult = await query.executeWithPayment(
        requirement.extra?.quoteId || '',
        txHash,
        requirement.network
      );

      return paidResult.records;
    }
    throw error;
  }
}
```

## executeWithPayment

The `executeWithPayment()` method on QueryBuilder retries a query with payment proof:

```typescript theme={null}
const result = await client.queryBuilder()
  .collection('premium_data')
  .selectAll()
  .executeWithPayment<MyType>(
    quoteId,      // From PaymentRequiredError.quote.quoteId
    txHash,       // Transaction hash from your payment
    network       // Optional: network identifier
  );
```

### Parameters

| Parameter      | Type     | Description                              |
| -------------- | -------- | ---------------------------------------- |
| `quoteId`      | `string` | Quote ID from the `PaymentRequiredError` |
| `paymentProof` | `string` | Transaction hash from the payment        |
| `network`      | `string` | Optional network identifier              |

### Return Value

Returns `QueryResponse<T>` with the same structure as `execute()`.

## Error Types

```typescript theme={null}
import {
  PaymentRequiredError,
  PaymentVerificationError,
  OnDBError
} from '@ondb/sdk';

try {
  const result = await client.queryBuilder()
    .collection('paid_content')
    .selectAll()
    .execute();
} catch (error) {
  if (error instanceof PaymentRequiredError) {
    // Payment is required - paymentRequired has all details
    const paymentInfo = error.paymentRequired;
    console.log('Error:', paymentInfo.error);
    const requirement = paymentInfo.accepts[0];
    console.log('Cost:', requirement.maxAmountRequired, requirement.tokenSymbol);
    console.log('Pay to:', requirement.payTo);
  } else if (error instanceof PaymentVerificationError) {
    // Payment was made but verification failed
    console.log('Verification failed for tx:', error.txHash);
  } else if (error instanceof OnDBError) {
    console.log('OnDB error:', error.code, error.statusCode);
  }
}
```

## Type-Safe Payment Handling

```typescript theme={null}
import { PaymentRequiredError, QueryResponse } from '@ondb/sdk';

interface PremiumContent {
  title: string;
  content: string;
  price: number;
}

async function fetchPremiumContent(): Promise<PremiumContent[] | null> {
  const query = client.queryBuilder()
    .collection('premium')
    .selectAll();

  try {
    const result = await query.execute<PremiumContent>();
    return result.records;
  } catch (error) {
    if (error instanceof PaymentRequiredError) {
      const requirement = error.paymentRequired.accepts[0];
      const txHash = await processPayment(requirement);

      const paidResult = await query.executeWithPayment<PremiumContent>(
        requirement.extra?.quoteId || '',
        txHash,
        requirement.network
      );
      return paidResult.records;
    }
    throw error;
  }
}
```

## Use Cases

| Use Case             | Description                                        |
| -------------------- | -------------------------------------------------- |
| **Premium Content**  | Charge for access to exclusive data                |
| **API Monetization** | Monetize data access with per-query pricing        |
| **Cost Recovery**    | Recover computational costs for expensive queries  |
| **Tiered Access**    | Free basic queries, paid for detailed fields       |
| **Data Marketplace** | Build marketplaces where data providers set prices |

## Next Steps

<CardGroup cols={2}>
  <Card title="Cost Estimation" icon="calculator" href="/payments/cost-estimation">
    Estimate operation costs
  </Card>

  <Card title="Write Payments" icon="credit-card" href="/payments/write-payments">
    Write operation payments
  </Card>
</CardGroup>
