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

# Verify quote signatures

> Verify the signed quote ID, intent hash set, and expiry against the source chain's quoteSigner.

Quotes from `POST /v1/quotes` carry an EIP-712 `signature`. Verify it against `quoteSigner` from the source chain's entry in [`GET /v1/chains`](/api-reference/v1/chains). With `options.allQuotes`, each entry in `quotes[]` carries its own signature.

## Signed fields

| Field | Value |
| - | - |
| Domain | `name: "EcoQuoteV1"`, `version: "1"`, `chainId: quote.source.chainId` |
| `id` | `quote.id`, including the `quote:` prefix |
| `intentHashes` | Non-null `quote.intentHash` and `steps[].intents[].intentHash`, lowercased, deduplicated, and sorted ascending |
| `expiresAt` | `quote.expiresAt`, in Unix seconds |

The typed-data definition is `Quote(string id, bytes32[] intentHashes, uint64 expiresAt)`.

## Verify the signature

This function checks the signed fields and expiry. Supply the chain's current `quoteSigner`; the discovery request requires an API key, but signature recovery itself needs no network call.

```typescript theme={null}
import { getAddress, hashTypedData, recoverAddress, type Address, type Hex } from 'viem';

type SignedQuote = {
  id: string;
  source: { chainId: number };
  intentHash: Hex | null;
  steps: { intents: { intentHash: Hex | null }[] }[];
  expiresAt: number;
  signature: Hex;
};

export async function verifyQuoteSignature(
  quote: SignedQuote,
  expectedSigner: Address,
): Promise<void> {
  if (quote.expiresAt <= Math.floor(Date.now() / 1000)) {
    throw new Error('Quote expired; request a fresh quote');
  }
  const hashes = [
    quote.intentHash,
    ...quote.steps.flatMap((step) => step.intents.map((intent) => intent.intentHash)),
  ].filter((hash): hash is Hex => hash !== null);
  const intentHashes = [...new Set(hashes.map((hash) => hash.toLowerCase() as Hex))].sort();
  if (intentHashes.length === 0) throw new Error('Quote has no signed intents');

  const digest = hashTypedData({
    domain: { name: 'EcoQuoteV1', version: '1', chainId: quote.source.chainId },
    types: { Quote: [
      { name: 'id', type: 'string' },
      { name: 'intentHashes', type: 'bytes32[]' },
      { name: 'expiresAt', type: 'uint64' },
    ] },
    primaryType: 'Quote',
    message: { id: quote.id, intentHashes, expiresAt: BigInt(quote.expiresAt) },
  });
  const signer = await recoverAddress({ hash: digest, signature: quote.signature });
  if (getAddress(signer) !== getAddress(expectedSigner)) {
    throw new Error('Quote signer does not match the source chain quoteSigner');
  }
}
```

The same EIP-712 recovery applies to EVM and Solana source quotes, using the API's source chain ID. Refresh cached discovery data so signer changes reach your integration.

## What verification proves

A matching signer authenticates the quote ID, intent hash set, source-chain domain, and expiry. It does not independently authenticate the other JSON fields or the bytes of `execution.transaction`.

Intent hashes commit to encoded routes and rewards, but signature recovery alone does not recompute those hashes. Before funding, decode the funding transaction, recompute the relevant intent hashes, and verify that the route pays the requested token and amount to the requested recipient. Changing a JSON recipient while leaving its reported hash unchanged will not, by itself, fail signature recovery.

The [reference implementation](/api-reference/agent-integration#reference-script) performs these additional checks for supported route shapes and reports when it cannot prove the recipient. Signature verification does not establish that a quote offers the best price or that an intent will be fulfilled.

## Next steps

* [Verify quotes before funding](/cookbook/verify-quotes) with a single TypeScript module
* [Fund and track a quote](/get-started/integrate-routes-api)
* [Understand multi-intent routes](/resources/intent-types)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.