> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowsign.app/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Flowsign is one word with a lowercase s.
> The REST API base URL is https://my.flowsign.app and every endpoint lives under /api/v1.
> When answering API questions, cite the HTTP method and endpoint path.
> API access needs the Enterprise plan and an API key with the API access permission.

# Events

> Every webhook event and the fields in its payload.

Every delivery has the same envelope. `event` is one of the names below and `data` is that event's payload.

```json theme={null}
{
  "event": "SESSION_COMPLETED",
  "timestamp": "2026-09-17T01:15:02.318Z",
  "data": { ... }
}
```

<ResponseField name="event" type="string" required>
  The event name.
</ResponseField>

<ResponseField name="timestamp" type="string" required>
  When the event was raised, ISO 8601 in UTC.
</ResponseField>

<ResponseField name="data" type="object" required>
  Event-specific payload, documented per event below.
</ResponseField>

<ResponseField name="test" type="boolean">
  `true` on a sample sent with **Send test event**. Absent on real events.
</ResponseField>

Events about one package are recorded in the order they happened, so an endpoint receives `PACKAGE_SENT` before that package's `SESSION_SENT` events, and `SESSION_DECLINED` before `PACKAGE_DECLINED` before the `SESSION_CANCELLED` events that follow it. A retried delivery can still arrive after later ones, so order by `timestamp` when it matters.

Package events describe the package as a whole. Session events describe one recipient's turn on a package. A recipient's `recipientName` and `recipientEmail` are nullable because a session can exist before the recipient is known.

Every event also carries the package's custom field values:

<ResponseField name="metadata" type="object" required>
  The package's custom field values, keyed by the custom field's key. Only fields with a value appear; `{}` when none are set. Keys are managed under **Settings > Custom fields**.
</ResponseField>

The same schemas are published in the OpenAPI spec as `WebhookPayload_<EVENT>` components, so you can generate types for your listener.

## Package events

### PACKAGE\_SENT

Raised once when a package is sent and its signing sessions are created. The package already reads `IN_PROGRESS` when this arrives.

<ResponseField name="packageId" type="string" required />

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="signerCount" type="integer" required>
  Number of recipients who must act on the package.
</ResponseField>

<ResponseField name="sessionsSent" type="integer" required>
  Number of sessions invited immediately. Lower than `signerCount` when recipients sign in order.
</ResponseField>

```json theme={null}
{
  "event": "PACKAGE_SENT",
  "timestamp": "2026-09-17T01:12:50.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "signerCount": 2,
    "sessionsSent": 1,
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### PACKAGE\_COMPLETED

Raised when the last recipient finishes and the package becomes `COMPLETED`.

<ResponseField name="packageId" type="string" required />

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="completedAt" type="string" required>
  ISO 8601 timestamp.
</ResponseField>

```json theme={null}
{
  "event": "PACKAGE_COMPLETED",
  "timestamp": "2026-09-17T03:40:11.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "completedAt": "2026-09-17T03:40:10.884Z",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### PACKAGE\_DECLINED

Raised when a recipient's decline ends the package as `DECLINED`. A `SESSION_CANCELLED` event follows for every other recipient whose session was open.

<ResponseField name="packageId" type="string" required />

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="reason" type="string | null" required>
  The reason the recipient gave, if any.
</ResponseField>

```json theme={null}
{
  "event": "PACKAGE_DECLINED",
  "timestamp": "2026-09-17T02:05:30.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "reason": "Start date is wrong",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### PACKAGE\_VOIDED

Raised when a package is voided by a member or through the API. A `SESSION_CANCELLED` event follows for every recipient whose session was open.

<ResponseField name="packageId" type="string" required />

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="voidedBy" type="string" required>
  Email address of the member who voided it, or `system`.
</ResponseField>

```json theme={null}
{
  "event": "PACKAGE_VOIDED",
  "timestamp": "2026-09-17T02:30:00.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "voidedBy": "ops@example.com",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### PACKAGE\_EXPIRED

Raised when a sent package passes its expiry date unsigned. A package that expires before it was ever sent (a draft, or one still scheduled) raises nothing. A `SESSION_CANCELLED` event follows for every recipient whose session was open.

<ResponseField name="packageId" type="string" required />

<ResponseField name="packageTitle" type="string" required />

```json theme={null}
{
  "event": "PACKAGE_EXPIRED",
  "timestamp": "2026-10-17T00:00:05.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### PACKAGE\_ON\_HOLD

Raised when a package out for signing is put on hold by a member or through the API. Recipients can't sign until it is resumed.

<ResponseField name="packageId" type="string" required />

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="heldBy" type="string" required>
  Email address of the member who put it on hold, or `system`.
</ResponseField>

```json theme={null}
{
  "event": "PACKAGE_ON_HOLD",
  "timestamp": "2026-09-17T02:10:00.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "heldBy": "ops@example.com",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### PACKAGE\_RESUMED

Raised when a package on hold goes back out for signing.

<ResponseField name="packageId" type="string" required />

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="resumedBy" type="string" required>
  Email address of the member who resumed it, or `system`.
</ResponseField>

<ResponseField name="expiresAt" type="string | null" required>
  The new expiry, ISO 8601, pushed back by the time the package spent on hold. Null when the package never expires.
</ResponseField>

```json theme={null}
{
  "event": "PACKAGE_RESUMED",
  "timestamp": "2026-09-18T09:00:00.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "resumedBy": "ops@example.com",
    "expiresAt": "2026-10-18T06:50:00.000Z",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### PACKAGE\_SCHEDULED

Raised when a package is scheduled to send later, and again when a scheduled package is moved to a new time. `PACKAGE_SENT` follows when it sends.

<ResponseField name="packageId" type="string" required />

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="scheduledAt" type="string" required>
  When the package will send, ISO 8601.
</ResponseField>

```json theme={null}
{
  "event": "PACKAGE_SCHEDULED",
  "timestamp": "2026-09-17T01:00:00.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "scheduledAt": "2026-09-20T20:00:00.000Z",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### PACKAGE\_DELETED

Raised when a package that was scheduled, out for signing or on hold is deleted. Deleting a draft, or a package that had already completed, been declined or voided, raises nothing. A `SESSION_CANCELLED` event follows for every recipient whose session was open. The package is gone by the time this arrives, so `GET /api/v1/packages/{packageId}` returns 404.

<ResponseField name="packageId" type="string" required />

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="deletedBy" type="string" required>
  Email address of the member who deleted it.
</ResponseField>

```json theme={null}
{
  "event": "PACKAGE_DELETED",
  "timestamp": "2026-11-02T04:12:00.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "deletedBy": "ops@example.com",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

## Session events

All session events share these fields:

<ResponseField name="packageId" type="string" required />

<ResponseField name="sessionId" type="string" required>
  Matches `recipientSessions[].id` on `GET /api/v1/packages/{packageId}`.
</ResponseField>

<ResponseField name="recipientName" type="string | null" required />

<ResponseField name="recipientEmail" type="string | null" required />

### SESSION\_SENT

Raised when a recipient's invitation is sent. In a sequential package this happens when it becomes their turn.

<ResponseField name="packageTitle" type="string" required />

```json theme={null}
{
  "event": "SESSION_SENT",
  "timestamp": "2026-09-17T01:12:50.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "sessionId": "ses_71ab",
    "recipientName": "Ana Reid",
    "recipientEmail": "ana@example.com",
    "packageTitle": "Employment agreement: Ana Reid",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### SESSION\_OPENED

Raised when the recipient opens their session. Carries the shared fields only.

```json theme={null}
{
  "event": "SESSION_OPENED",
  "timestamp": "2026-09-17T01:20:14.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "sessionId": "ses_71ab",
    "recipientName": "Ana Reid",
    "recipientEmail": "ana@example.com",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### SESSION\_COMPLETED

Raised when the recipient finishes their session.

<ResponseField name="packageTitle" type="string" required />

```json theme={null}
{
  "event": "SESSION_COMPLETED",
  "timestamp": "2026-09-17T01:26:02.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "sessionId": "ses_71ab",
    "recipientName": "Ana Reid",
    "recipientEmail": "ana@example.com",
    "packageTitle": "Employment agreement: Ana Reid",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### SESSION\_DECLINED

Raised when the recipient declines to sign. A `PACKAGE_DECLINED` event follows when the decline ends the package.

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="reason" type="string | null" required>
  The reason the recipient gave, if any.
</ResponseField>

```json theme={null}
{
  "event": "SESSION_DECLINED",
  "timestamp": "2026-09-17T02:05:29.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "sessionId": "ses_71ab",
    "recipientName": "Ana Reid",
    "recipientEmail": "ana@example.com",
    "packageTitle": "Employment agreement: Ana Reid",
    "reason": "Start date is wrong",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### SESSION\_REMINDED

Raised each time a recipient is sent a reminder, whether a member sent it or the package's reminder schedule did.

<ResponseField name="packageTitle" type="string" required />

<ResponseField name="trigger" type="string" required>
  `manual` when a member sent the reminder, `automatic` when the reminder schedule did.
</ResponseField>

```json theme={null}
{
  "event": "SESSION_REMINDED",
  "timestamp": "2026-09-20T01:12:50.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "sessionId": "ses_71ab",
    "recipientName": "Ana Reid",
    "recipientEmail": "ana@example.com",
    "packageTitle": "Employment agreement: Ana Reid",
    "trigger": "automatic",
    "metadata": { "employee_id": "E-1042" }
  }
}
```

### SESSION\_CANCELLED

Raised for each recipient whose session was open, meaning sent and not yet finished, when the package is declined by someone else, voided, expires or is deleted, or when a correction removes the recipient. A recipient whose turn had not come yet raises nothing. When a correction removes the recipient, their session is deleted, so its `sessionId` no longer appears on the package.

<ResponseField name="packageTitle" type="string" required />

```json theme={null}
{
  "event": "SESSION_CANCELLED",
  "timestamp": "2026-09-17T02:30:00.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "sessionId": "ses_71ab",
    "recipientName": "Ana Reid",
    "recipientEmail": "ana@example.com",
    "packageTitle": "Employment agreement: Ana Reid",
    "metadata": { "employee_id": "E-1042" }
  }
}
```
