# Error Handling and Recovery

#### HTTP Status Codes

| Code | Meaning                    |
| ---- | -------------------------- |
| 400  | Invalid request parameters |
| 403  | Invalid or missing api-key |
| 404  | Resource not found         |
| 429  | Rate limit exceeded        |
| 500  | Internal server error      |

#### Error Response Format

All errors return a JSON object with an `error` field containing a `message`:

```json
{
  "error": {
    "message": "description of the error"
  }
}
```

For application-level errors (e.g. `PusherError`), the response also includes a `code` field:

```json
{
  "error": {
    "code": "NOT_SMART_ACCOUNT",
    "message": "Address has no deployed code — not a smart account"
  }
}
```

#### Recovery Endpoints

When a cross-chain transaction gets stuck, these endpoints help resolve the situation.

**POST /tx/create/emergency**

Build a transaction to return funds to the sender when delivery is stuck (`destination.emergency` is `true`).

| Field       | Type   | Description                                            |
| ----------- | ------ | ------------------------------------------------------ |
| `requestId` | string | The request ID from the `ComplexOpProcessed` event     |
| `signature` | string | EIP-191 signature from the original sender (see below) |

**Generating the signature:**

The server expects an EIP-191 personal sign over the keccak256 hash of the `requestId` string. The signer must be the original sender address.

```js
// Using ethers.js
import { solidityPackedKeccak256, getBytes } from "ethers";

const messageHash = solidityPackedKeccak256(["string"], [requestId]);
const signature = await signer.signMessage(getBytes(messageHash));
```

```ts
// Using viem
import { keccak256, encodePacked, toBytes } from "viem";

const messageHash = keccak256(encodePacked(["string"], [requestId]));
const signature = await walletClient.signMessage({
  message: { raw: toBytes(messageHash) },
});
```

**Full example:**

```js
// Check if emergency is available
const status = await fetch(`${API}/transaction/${requestId}`).then((r) => r.json());
if (!status.destination.emergency) {
  console.log("Emergency not yet available — wait at least 30 minutes");
}

// Generate signature
const messageHash = solidityPackedKeccak256(["string"], [requestId]);
const signature = await signer.signMessage(getBytes(messageHash));

// Build emergency transaction
const res = await fetch(`${API}/tx/create/emergency`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ requestId, signature }),
});
const emergencyTx = await res.json();

// Send on-chain
await wallet.sendTransaction({
  to: emergencyTx.to,
  data: emergencyTx.data,
  value: emergencyTx.value,
});
```

**POST /tx/create/retry**

Retry a failed delivery. Uses the same signature format as the emergency endpoint.

| Field       | Type   | Description                                        |
| ----------- | ------ | -------------------------------------------------- |
| `requestId` | string | The request ID from the `ComplexOpProcessed` event |
| `signature` | string | EIP-191 signature from the original sender         |

```js
const messageHash = solidityPackedKeccak256(["string"], [requestId]);
const signature = await signer.signMessage(getBytes(messageHash));

const res = await fetch(`${API}/tx/create/retry`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ requestId, signature }),
});
const retryTx = await res.json();
// Send retryTx on-chain
```

**POST /tx/create/resumeBr**

Resume a paused bridge relay.

```json
{
  "requestId": "0x..."
}
```

**POST /tx/create/cancelBr**

Cancel a pending bridge relay.

```json
{
  "requestId": "0x..."
}
```
