# Core

> Compose endpoint management and PostgreSQL delivery.

Source: https://good-webhooks.dev/docs/reference/core



The root entry point combines endpoint management and PostgreSQL delivery in one client.

```ts
import {
  createWebhooks,
  createDelivery,
  generateEncryptionKey,
  verifyWebhook,
  WebhookError,
} from 'good-webhooks'
import type {
  WebhookOptions,
  Webhooks,
  WebhookClient,
  EndpointInput,
  EndpointPatch,
  WebhookErrorCode,
} from 'good-webhooks'
```

The root also exports the shared types listed under [other root exports](#other-root-exports). For the step-by-step setup, see [installation](https://good-webhooks.dev/docs/installation.md).

## createWebhooks [#createwebhooks]

```ts
createWebhooks<const E extends EventDefinitions>(options: WebhookOptions<E>): Webhooks<E>
```

```ts title="webhooks.ts"
import { createWebhooks } from 'good-webhooks'
import { Pool } from 'pg'
import { z } from 'zod'

export const pool = new Pool({ connectionString: process.env.DATABASE_URL })

export const webhooks = createWebhooks({
  database: pool,
  encryptionKey: process.env.WEBHOOK_ENCRYPTION_KEY!,
  events: {
    'invoice.paid': z.object({ invoiceId: z.string(), amount: z.number().int() }),
  },
})
```

`WebhookOptions<E>` accepts every [delivery option](https://good-webhooks.dev/docs/reference/delivery.md#createdelivery) except `source`, plus these fields:

| Field           | Type                   | Meaning                                                                                              |
| --------------- | ---------------------- | ---------------------------------------------------------------------------------------------------- |
| `encryptionKey` | `string \| Uint8Array` | Required for the default PostgreSQL management provider. Base64-encoded 32 bytes or a 32-byte array. |
| `management`    | `EndpointManagement`   | Optional existing provider. Its source supplies recipients and current endpoint state.               |

Construction does not open connections, apply migrations, or start a worker.

* **Without `management`**, the constructor creates standalone PostgreSQL management from `database`, `schema`, the configured event names, `encryptionKey`, and `allowLocalhost`. `schema` then applies to both the management and delivery tables.
* **With `management`**, that provider keeps its own database, schema, encryption, and URL-validation configuration. Core options do not reconfigure it, and `encryptionKey` is unused.

Invalid options throw `INVALID_CONFIG`: a missing event map, a malformed key, a database without `query()` and `connect()`, or any [delivery option](https://good-webhooks.dev/docs/reference/delivery.md#createdelivery) out of range.

**Rotating the storage encryption key with createWebhooks**

The default provider has no `decryptionKeys` option through this constructor. Create a provider with [`createPostgresManagement`](https://good-webhooks.dev/docs/reference/postgres.md), which accepts old keys, and pass it as `management`. See [key rotation](https://good-webhooks.dev/docs/operations/key-rotation.md).

## Returned client [#returned-client]

The client exposes `publish`, `deliveries`, `deliverySettings`, and `worker` from the [delivery engine](https://good-webhooks.dev/docs/reference/delivery.md), plus these members:

| Member                                     | Behavior                                                                                         |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------ |
| `endpoints.create(input)`                  | Creates an endpoint and returns `{ endpoint, secret }`.                                          |
| `endpoints.list()`                         | Returns all nondeleted endpoints in application scope.                                           |
| `endpoints.get(id)`                        | Returns one endpoint, including its deleted state.                                               |
| `endpoints.update(id, patch)`              | Changes URL, description, or subscribed event names.                                             |
| `endpoints.pause(id)`                      | Records paused state.                                                                            |
| `endpoints.resume(id)`                     | Records active state after URL validation.                                                       |
| `endpoints.remove(id)`                     | Records permanent deletion and clears stored signing secrets.                                    |
| `endpoints.rotateSecret(id, { graceMs? })` | Returns a new signing secret and the endpoint.                                                   |
| `check()`                                  | Checks the default management provider, if constructed here, then delivery schema compatibility. |
| `forScope(scope)`                          | Returns the same publication, history, settings, and endpoint methods bound to one named scope.  |

### endpoints [#endpoints]

```ts
import { webhooks } from './webhooks.js'

const { endpoint, secret } = await webhooks.endpoints.create({
  url: 'https://receiver.example/webhooks',
  eventTypes: ['invoice.paid'],
})
await webhooks.endpoints.rotateSecret(endpoint.id, { graceMs: 60 * 60 * 1000 })
```

Endpoint methods follow the [management contract and limits](https://good-webhooks.dev/docs/reference/management.md#endpointmanagement), including its errors. `EndpointInput<E>` and `EndpointPatch<E>` restrict subscriptions to event names in `E`. `removeScope` and `reencrypt` are direct provider operations, not members of this client. The [endpoints guide](https://good-webhooks.dev/docs/guides/endpoints.md) covers the lifecycle.

### forScope [#forscope]

```ts
import { webhooks } from './webhooks.js'

const customer = webhooks.forScope({ type: 'organization', id: 'org_123' })
await customer.publish({ type: 'invoice.paid', data: { invoiceId: 'inv_1', amount: 4200 } })
await customer.endpoints.list()
```

`forScope` validates and snapshots its scope, so later changes to the argument have no effect. An invalid scope throws `INVALID_INPUT`. It does not authorize a caller. See [scopes](https://good-webhooks.dev/docs/concepts/scopes.md).

The scoped client has no `worker` or `check`: those operate at installation level. `WebhookClient<E>` is its type.

### check [#check]

```ts
import { webhooks } from './webhooks.js'

await webhooks.check() // Throws SCHEMA_MISMATCH if tables are missing or outdated.
```

`check()` never applies migrations. When a provider is injected, it does not call that provider's optional health checks. The host stays responsible for checking its management storage.

## generateEncryptionKey [#generateencryptionkey]

```ts
generateEncryptionKey(): string
```

```ts
import { generateEncryptionKey } from 'good-webhooks'

console.log(generateEncryptionKey()) // Store once in your secret manager.
```

Returns 32 cryptographically random bytes encoded as base64. The key is the storage encryption key for standalone management signing secrets. It is distinct from the endpoint's `whsec_` signing secret. Keep it outside the database.

## Other root exports [#other-root-exports]

| Export           | Documented at                                    |
| ---------------- | ------------------------------------------------ |
| `createDelivery` | [Delivery entry point](https://good-webhooks.dev/docs/reference/delivery.md) |
| `verifyWebhook`  | [Receiver entry point](https://good-webhooks.dev/docs/reference/verify.md)   |
| `WebhookError`   | [Errors](https://good-webhooks.dev/docs/reference/errors.md)                 |

`parseWebhook` is available only from `good-webhooks/verify`.

The root also exports these types:

| Group       | Types                                                                                                                                   |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Events      | `EventDefinitions`, `EventName`, `JsonValue`, `PublishInput`, `PublishOptions`, `PublishResult`                                         |
| Database    | `SqlClient`, `DatabaseClient`, `Database`                                                                                               |
| Endpoints   | `Endpoint`, `EndpointStatus`, `EndpointWithSecret`, `EndpointInput`, `EndpointPatch`                                                    |
| Delivery    | `Delivery`, `DeliveryDetail`, `DeliveryStatus`, `DeliveryQuery`, `Attempt`, `Page`, `WorkerResult`, `DeliveryOptions`, `DeliveryEngine` |
| Composition | `WebhookOptions`, `Webhooks`, `WebhookClient`, `EndpointManagement`, `EndpointSource`, `EndpointResolution`, `ManagementScope`, `Scope` |
| Errors      | `WebhookErrorCode`                                                                                                                      |
