# Error Handling

The Fuul API uses standard HTTP status codes to indicate success or failure. The SDK catches API errors and throws typed error classes for common failure modes.

## HTTP status codes

| Status | Meaning                                              |
| ------ | ---------------------------------------------------- |
| `200`  | Success                                              |
| `400`  | Bad Request — invalid parameters or validation error |
| `401`  | Unauthorized — missing or invalid API key            |
| `403`  | Forbidden — API key lacks required permissions       |
| `404`  | Not Found                                            |
| `409`  | Conflict — duplicate resource                        |
| `429`  | Too Many Requests — rate limit exceeded              |
| `500`  | Server Error                                         |

## SDK error types

The SDK throws these error classes for affiliate code operations. Each extends `Error` and sets a `.name` property:

| Error class             | `.name`                   | When thrown                                                                      |
| ----------------------- | ------------------------- | -------------------------------------------------------------------------------- |
| `ValidationError`       | `'ValidationError'`       | Invalid characters in the code. Has an `errors: string[]` property with details. |
| `InvalidSignatureError` | `'InvalidSignatureError'` | Signature doesn't match the address and message                                  |
| `AddressInUseError`     | `'AddressInUseError'`     | Address already has a code registered. Has an `address` property.                |
| `CodeInUseError`        | `'CodeInUseError'`        | Code is already taken. Has a `code` property.                                    |

These are exported from `@fuul/sdk` and can be used with `instanceof`:

```typescript
import { Fuul, CodeInUseError, AddressInUseError, ValidationError, InvalidSignatureError } from '@fuul/sdk';

try {
  await Fuul.createAffiliateCode({
    userIdentifier: '0x1234...',
    identifierType: 'evm_address',
    signature: '0xabc...',
    code: 'my-code',
  });
} catch (error) {
  if (error instanceof CodeInUseError) {
    // Code already taken — prompt the user to choose another
    console.log('Taken code:', error.code);
  } else if (error instanceof AddressInUseError) {
    // Address already has a code
    console.log('Address:', error.address);
  } else if (error instanceof ValidationError) {
    // Invalid code format
    console.log('Validation errors:', error.errors);
  } else if (error instanceof InvalidSignatureError) {
    // Signature verification failed
  } else {
    // Unexpected error
    console.error('Unexpected error:', error);
  }
}
```

{% hint style="info" %}
For API calls not related to affiliate codes, the SDK throws standard `Error` objects with the API error message.
{% endhint %}

## API key permissions reference

| Endpoint category                                | Required key type               |
| ------------------------------------------------ | ------------------------------- |
| Read data (leaderboards, rewards, conversions)   | Any key type                    |
| Send tracking events (pageview, connect\_wallet) | `send:tracking_event` or higher |
| Send trigger events (custom offchain events)     | `send:trigger_event`            |
| Manage audiences, webhooks, set referrers        | `service_role`                  |

For full details on key types, see [API Key Management](https://docs.fuul.xyz/developer-guide/api-key-management).
