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

# Purchase Permits

> Cryptographically signed authorizations that connect compliance verification to onchain purchases.

## Overview

Purchase permits are signed messages that authorize specific wallet addresses to purchase tokens for verified entities. They serve as the bridge between Sonar's compliance verification and your onchain sale contract.

Each permit proves that an entity has completed the required verification and is authorized to make a specific purchase with given funding bounds.

## Permit Architecture

```mermaid theme={null}
sequenceDiagram
    participant F as Frontend
    participant S as Sonar API
    participant C as Contract
    
    F->>S: Request purchase permit
    S->>S: Verify entity eligibility and pre-purchase checks
    S->>S: Sign permit with private key
    S->>F: Return signed permit
    F->>C: Call contract with permit
    C->>C: Verify ECDSA signature
    C->>C: Execute purchase
```

Permits are **short-lived** (10 minutes) to ensure fresh compliance status. Participants can use multiple permits during a sale (e.g., to update bids in an auction), but each permit expires quickly to maintain security.

## Permit Structure

Sonar sets different fields in the permit based on your sale configuration:

```typescript theme={null}
{
    saleSpecificEntityID: "0x1234567890abcdef1234567890abcdef",
    saleUUID: "0xabcdef1234567890abcdef1234567890",
    wallet: "0x742d35Cc6364C0532d0ef6b1234567890abcdef",
    expiresAt: 1704067200,
    minAmount: 1000000000,
    maxAmount: 10000000000,
    minPrice: 1000000000,
    maxPrice: 10000000000,
    opensAt: 1704060000,
    closesAt: 1704153600,
    payload: "0x"
}
```

### Field Reference

| Field                  | Description                                                                                                                                |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `saleSpecificEntityID` | Sale-specific entity identifier. The same entity has different IDs across different sales for privacy.                                     |
| `saleUUID`             | Your sale's unique identifier. The contract should verify this matches a hardcoded value.                                                  |
| `wallet`               | The authorized wallet address. The contract should verify this matches the transaction sender.                                             |
| `expiresAt`            | Unix timestamp when the permit expires (10 minutes from issuance). The contract should verify this is in the future.                       |
| `minAmount`            | Minimum total commitment required from this entity. Set based on your sale's commitment limits.                                            |
| `maxAmount`            | Maximum total commitment allowed for this entity. Used to enforce whale caps and per-entity limits.                                        |
| `minPrice`             | Minimum bid price allowed (for auctions). For fixed-price sales, this equals the sale price.                                               |
| `maxPrice`             | Maximum bid price allowed (for auctions). For fixed-price sales, this equals the sale price.                                               |
| `opensAt`              | Unix timestamp when the permit becomes valid (inclusive). Enables time-gated access windows.                                               |
| `closesAt`             | Unix timestamp when the permit stops being valid (exclusive). The contract should verify the current time is within `[opensAt, closesAt)`. |
| `payload`              | Additional data for custom logic (e.g., forced lockup preferences).                                                                        |

<Info>
  Price fields are denominated in the auction's [bid increment](/sonar/planning/pricing-strategies#auction-parameters).
  For example, if the bid increment is \$0.01, then a price of 100 represents a willingness to pay \$1.00.
</Info>

<Info>
  Limits are enforced at the **entity level**, not the wallet level. A participant using multiple wallets still has a single limit across all of them. Your contract should track commitments by `saleSpecificEntityID` and validate that the entity's total stays within the min/max bounds.
</Info>

## Common Issues

**Signature Verification Failures**

Most permit issues stem from signature verification problems:

1. **Wrong signer address**: Ensure your contract has the correct Sonar signer address
2. **Struct encoding**: Permit structure must exactly match Solidity definition
3. **Sale UUID mismatch**: Verify your sale UUID matches exactly

Debug by logging the recovered signer address in your contract.

**Expiration Handling**

Permits expire in 10 minutes:

1. **Generate permits just-in-time**: Don't fetch permits during page load
2. **Implement retry logic**: Regenerate expired permits automatically
3. **Handle expired permit errors gracefully**: Provide clear retry options

## See Also

<CardGroup cols={2}>
  <Card title="Custom Contracts" href="/sonar/integration-guides/custom-contracts" icon="file-code">
    Learn how to validate permits in your custom sale contract
  </Card>

  <Card title="Frontend Integration" href="/sonar/integration-guides/frontend-overview" icon="browser">
    Generate and use permits in your application
  </Card>

  <Card title="Entities" href="/sonar/core-features/entities" icon="users">
    Understanding entities and why limits are per-entity
  </Card>
</CardGroup>
