Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,65 @@ Siren ships official SDKs in three languages, all built against the same API:
Contributions are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to clone, build, test,
and open a pull request. Please also review our [Code of Conduct](./CODE_OF_CONDUCT.md).

## Error handling

API and network failures throw a typed subclass of `SirenError`. Catch the base class to
handle any SDK error, or branch on a specific subclass. Every error has a `message`; `code`
(the API's machine-readable error code) and `statusCode` (the HTTP status) are set when the
failing response provides them — `ConnectionError` and `SignatureVerificationError`, for
example, carry no `statusCode`:

| Error | When it's thrown |
|---|---|
| `AuthenticationError` | Missing or invalid API key (401) |
| `PermissionError` | Key lacks permission for the operation (403) |
| `NotFoundError` | The requested resource does not exist (404) |
| `ValidationError` | Request payload failed validation (422) |
| `BadRequestError` | Malformed request (400) |
| `ConflictError` | Conflicting state, e.g. a duplicate (409) |
| `RateLimitError` | Rate limit exceeded (429); honors `Retry-After` |
| `ApiError` | Unexpected server error (5xx) |
| `ConnectionError` | Network failure reaching Siren |
| `SignatureVerificationError` | A webhook signature did not verify |

Two exceptions to the subclass rule: constructing a client without an `apiKey` throws the
base `SirenError` itself, and `webhooks.constructEvent` throws a native `SyntaxError` — not
a `SirenError` — when a correctly signed body is not valid JSON.

```ts
import {
Siren,
SirenError,
RateLimitError,
ValidationError,
NotFoundError,
} from '@novatorius/siren';

const siren = new Siren({ apiKey: process.env.SIREN_API_KEY! });

try {
await siren.events.sale({
source: 'stripe',
externalId: 'cs_test_a1b2c3',
total: 49.99,
trackingId: 4021,
});
} catch (err) {
if (err instanceof RateLimitError) {
// already retried with backoff; back off further or queue for later
} else if (err instanceof ValidationError) {
console.error('Invalid payload:', err.message, err.code);
} else if (err instanceof NotFoundError) {
// nothing matched — e.g. a refund for a sale Siren never recorded
} else if (err instanceof SirenError) {
// statusCode/code are set when the API produced the failure
console.error(`Siren error ${err.statusCode ?? 'n/a'} (${err.name}):`, err.message);
} else {
throw err; // not a Siren error
}
}
```

## Resources

- [Siren homepage](https://sirenaffiliates.com)
Expand Down
Loading