# party

Define signing roles and signature requirements

Canonical URL: https://docs.paradoc.dev/sdk/artifacts/form/party/

Define party roles for signatories with signature configuration. Parties represent roles like "buyer", "seller", or "guarantor" that can be filled by persons or organizations at runtime.

Party data format is determined by `max`:

* `max = 1` (default): single party object with required `id`
* `max > 1`: array of party objects, each with required `id`

An empty list for a `max > 1` role counts as an absent role. A role whose `required` is `false`, or whose `required` expression evaluates to false, may be absent or empty; `min` then applies only to a list that names parties.

## Examples

### Creating parties

```ts
// Single signer with signature requirement
const buyer = party()
  .label('Buyer')
  .partyType('person')
  .signature({ required: true })
  .build()

// Organization signer with witness requirement
const company = party()
  .label('Company')
  .partyType('organization')
  .description('The selling organization')
  .signature({ required: true, witnesses: 1 })
  .build()

// Multiple allowed (e.g., co-signers)
const coOwners = party()
  .label('Co-owners')
  .min(1)
  .max(4)  // max > 1 enables array format
  .signature({ required: true })
  .build()

// Optional party (min: 0 allows empty)
const coSigner = party()
  .label('Co-signer')
  .min(0)
  .signature({ required: true })
  .build()

// Conditional requirement
const guarantor = party()
  .label('Guarantor')
  .required('needsGuarantor')
  .signature({ required: true })
  .build()

// Notarized signature
const affiant = party()
  .label('Affiant')
  .signature({ required: true, notarized: true })
  .build()
```

### Adding parties to forms

```ts
// Object pattern
const form = p.form({
  name: 'purchase-agreement',
  parties: {
    buyer: {
      label: 'Buyer',
      partyType: 'person',
      signature: { required: true }
    },
    seller: {
      label: 'Seller',
      partyType: 'any',
      signature: { required: true, witnesses: 2 }
    }
  }
})

// Builder pattern
const form = p.form()
  .name('purchase-agreement')
  .party('buyer', party()
    .label('Buyer')
    .partyType('person')
    .signature({ required: true })
    .build())
  .party('seller', party()
    .label('Seller')
    .signature({ required: true, witnesses: 2 })
    .build())
  .build()
```

## API

### Object Pattern

Create party definitions directly as objects:

```ts
const partyDef: FormParty = {
  label: 'Buyer',
  description: 'The purchasing party',
  partyType: 'person',
  min: 1,
  max: 1,  // default, single party
  required: true,
  signature: {
    required: true,
    witnesses: 1,
    notarized: false
  }
}
```

#### FormParty Properties

| Name | Type | Description |
| --- | --- | --- |
| `label` | `string` | Human-readable role name |
| `description?` | `string` | Description of this role |
| `partyType?` | `'person' \| 'organization' \| 'any'` | Constraint on party type |
| `min?` | `number` | Minimum parties required. Defaults to 1 |
| `max?` | `number` | Maximum parties allowed. Defaults to 1. When max > 1, party data must be an array |
| `required?` | `boolean \| string` | Whether this role is required. Can be an expression. |
| `signature?` | `FormSignature` | Signature requirements |
| `payment?` | `FormPayment` | Payment requirement |

#### FormSignature Properties

| Name | Type | Description |
| --- | --- | --- |
| `required?` | `boolean` | Whether signature is required for this role |
| `witnesses?` | `number` | Number of caller-declared witness attestations required for this signature |
| `notarized?` | `boolean` | Whether an attesting witness must be declared with notary status |

#### FormPayment Properties

| Name | Type | Description |
| --- | --- | --- |
| `required?` | `boolean` | Whether payment is required for this role |
| `amount` | `Money \| MoneyExpression` | Amount owed: a fixed Money value, or a MoneyExpression resolved from filled data at request time |

### Builder Pattern

Chain methods to build a party incrementally:

Start with `party()`. Each method returns `PartyBuilder` and can be chained.

| Method | Description |
| --- | --- |
| `label(value: string)` | Set role display name (required) |
| `description(value: string)` | Set role description |
| `partyType(value: 'person' \| 'organization' \| 'any')` | Constrain party type |
| `min(value: number)` | Set minimum parties required (default: 1) |
| `max(value: number)` | Set maximum parties allowed (default: 1). When > 1, party data is an array |
| `required(value?: boolean \| string)` | Mark as required (default: true). Accepts expression. |
| `signature(value: FormSignature)` | Set signature requirements |
| `payment(value: FormPayment)` | Set the payment requirement |
| `from(value: FormParty)` | Initialize from existing party |

Terminal methods return `FormParty`.

| Method | Description |
| --- | --- |
| `build()` | Build and validate |

### Static Methods

| Method | Returns | Description |
| --- | --- | --- |
| `parse(input: unknown)` | `FormParty` | Parse unknown input (throws on error) |
| `safeParse(input: unknown)` | `Result<FormParty>` | Parse unknown input (returns result object) |

## Party Types

| Type           | Description                             |
| -------------- | --------------------------------------- |
| `person`       | Individual person (natural person)      |
| `organization` | Company, business, or legal entity      |
| `any`          | Either person or organization (default) |

## Signature Requirements

Use the `signature` property to specify requirements for this party's signature:

```ts
// Basic signature requirement
party()
  .label('Signer')
  .signature({ required: true })
  .build()

// With witnesses
party()
  .label('Borrower')
  .signature({ required: true, witnesses: 2 })
  .build()

// Notarized signature
party()
  .label('Affiant')
  .signature({ required: true, notarized: true })
  .build()

// Notarized with witness
party()
  .label('Declarant')
  .signature({ required: true, witnesses: 1, notarized: true })
  .build()
```

## Multiple Parties

Allow multiple parties to fill a single role by setting `max > 1`:

```ts
const form = p.form()
  .name('joint-account')
  .party('accountHolders', party()
    .label('Account Holders')
    .min(1)   // At least 1 required
    .max(4)   // Up to 4 allowed (enables array format)
    .signature({ required: true })  // All must sign
    .build())
  .build()
```

When `max > 1`, the party data at runtime must be an array:

```ts
const filled = form.fill({
  fields: { /* ... */ },
  parties: {
    accountHolders: [
      { id: 'accountHolders-0', name: 'Jane Smith' },
      { id: 'accountHolders-1', name: 'John Smith' }
    ]
  }
})
```

## Conditional Parties

Use defs for conditional party requirements:

```ts
const form = p.form()
  .name('loan-application')
  .field('loanAmount', field.number().label('Loan amount').build())
  .def('needsGuarantor', 'fields.loanAmount > 100000')
  .party('borrower', party()
    .label('Borrower')
    .signature({ required: true })
    .build())
  .party('guarantor', party()
    .label('Guarantor')
    .required('needsGuarantor')
    .signature({ required: true })
    .build())
  .build()
```

## Runtime Party Types

At runtime, parties are represented using the `Party` and `RuntimeParty` types.

### Party

The base `Party` type is a union of `Person` or `Organization`:

```typescript
type Party = Person | Organization
```

Party type is inferred from shape:

* **Person**: Has `name` property (a natural person)
* **Organization**: Has `name` property plus `legalName`, `entityType`, etc.

### RuntimeParty

`RuntimeParty` extends `Party` with the `id` a filled form gives each party. Signatories, captures, and attestations reference a party by it:

```typescript
type RuntimeParty = (Person | Organization) & {
  id: string  // `<roleId>-<index>`, assigned by core
}
```

The id is always `{roleId}-{index}`, the party's position in its role. `fill`, `update`, `setParty`, `addParty`, and `runtimeFormFromJSON` assign it, so you can leave it out. An id you do supply must match that position, or the call throws. `removeParty` gives each later party the id of its new position and moves its signatories with it.

A party record holds only its `Person` or `Organization` members. A member the schema does not declare, such as `address` or `phone`, is refused. Declare those as fields beside the party instead; the [`Party`](/components/party) component prints them by path.

```ts
// Fill a form with party data (single parties)
const filled = form.fill({
  fields: { /* ... */ },
  parties: {
    buyer: {
      id: 'buyer-0',  // Optional: core assigns it
      name: 'John Smith',
      firstName: 'John',
      lastName: 'Smith'
    },
    seller: {
      id: 'seller-0',  // Optional: core assigns it
      name: 'Acme Corporation, Inc.',
      entityType: 'corporation'
    }
  }
})
```

You can also use the primitive builders with the `id` field:

```ts
const filled = form.fill({
  fields: { /* ... */ },
  parties: {
    buyer: {
      id: 'buyer-0',
      ...p.person().name('John Smith').build()
    },
    seller: {
      id: 'seller-0',
      ...p.organization()
        .name('Acme Corp')
        .legalName('Acme Corporation, Inc.')
        .build()
    }
  }
})
```

## Related

* [form](/sdk/artifacts/form) - Parent form artifact
* [person](/sdk/primitives/person) - Person primitive for filling party roles
* [organization](/sdk/primitives/organization) - Organization primitive for filling party roles
* [signing](/sdk/artifacts/form/signing) - Signing flow and signature types
* [Party Schema](/schemas/artifacts/form/party)
