# Broadcast Approve Tx

Non-custodial approvals, step 2 — submit the signature for the `txHashToSign` returned by Approve Token.

## Overview

When [Approve Token](https://docs.aureahub.com/docs/swap-approve.md) returns `requiresClientSigning: true`, sign its `txHashToSign` with the wallet key and send the signature here. You do not send a signed raw transaction. The API rebuilds the EIP-1559 transaction it prepared, checks that the signature recovers to the wallet's address, and broadcasts it.

- `v` is the recovery parity, `0` or `1`; `r` and `s` are `0x` + 64 hex characters.
- The prepared transaction expires 5 minutes after Approve Token created it (`expiresAt`).
- The response is `{ txHash, status: "pending" }`. Approvals do not create a transaction record, so confirm the approval with [Check Allowance](https://docs.aureahub.com/docs/swap-allowance.md) before executing the swap.
- Rate limit: 10 requests per 10 seconds.

> ⚠️ The prepared transaction is marked as used **before** the signature is checked. If a request is rejected with `422`, retrying with the same `preparedTxId` returns `409` — call Approve Token again to prepare a new transaction.

## Endpoint

### `POST /v1/swap/broadcast-approve`

Authentication: bearer token required.

Validates a client signature for a prepared ERC-20 approval and broadcasts the transaction.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `preparedTxId` | string (uuid) | yes | `preparedTxId` from Approve Token. |
| `v` | integer | yes | Signature recovery parity: `0` or `1`. |
| `r` | string | yes | `0x` + 64 hex characters. |
| `s` | string | yes | `0x` + 64 hex characters. |

**Responses**

`200` OK

```json
{
  "txHash": "0x…",
  "status": "pending"
}
```

`404` Not Found

```json
{
  "statusCode": 404,
  "error": "NotFoundError",
  "message": "Prepared transaction not found"
}
```

`422` Wrong Signer

```json
{
  "statusCode": 422,
  "error": "BlockchainError",
  "message": "Signature does not correspond to the expected wallet address",
  "code": "WRONG_SIGNER",
  "retryable": false,
  "details": { "code": "WRONG_SIGNER", "retryable": false }
}
```

## Errors

- `400` `Request validation failed` — the body does not match the schema.
- `404` `Prepared transaction not found` — unknown `preparedTxId`, or it belongs to another user.
- `409` `PREPARED_TX_ALREADY_USED` — this prepared transaction was already submitted.
- `410` `PREPARED_TX_EXPIRED` — more than 5 minutes have passed; call Approve Token again.
- `422` `SIGNATURE_DECODE_FAILED` — `v`, `r`, `s` could not be decoded. `422` `WRONG_SIGNER` — the signature does not recover to the wallet address.

Blockchain errors (`409`, `410`, `422`) carry `code` and `retryable` next to `statusCode`, `error` and `message`.

## Implementation

```javascript
import { SigningKey } from 'ethers';

// prepared = response of POST /v1/swap/approve with requiresClientSigning: true
async function broadcastApproval(token, prepared, privateKey) {
  const sig = new SigningKey(privateKey).sign(prepared.txHashToSign);

  const res = await fetch('https://api.aureahub.com/v1/swap/broadcast-approve', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`
    },
    body: JSON.stringify({
      preparedTxId: prepared.preparedTxId,
      v: sig.yParity, // 0 or 1
      r: sig.r,
      s: sig.s
    })
  });

  const body = await res.json();
  if (!res.ok) throw new Error(`${res.status} ${body.code ?? ''}: ${body.message}`);
  return body.txHash; // then poll /v1/swap/check-allowance
}
```

---

Web version: https://docs.aureahub.com/#swap-broadcast-approve
