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

# Ingest UBOs, Directors & Signatories

> Step-by-step guide for ingesting corporate members - UBOs, directors, and signatories - into Corsa.

This guide walks you through ingesting **Members** - the individuals and entities associated with corporate clients as Ultimate Beneficial Owners (UBOs), Directors, Officers, or Signatories.

Full API endpoint details are available in the [API Reference](https://api.corsa.finance/api-spec.json) (requires API credentials).

<Note>Before ingesting members, make sure the related corporate clients have already been ingested. See the [Ingesting Clients](/api/ingesting-clients) guide.</Note>

***

## Overview

Members represent the people and entities behind a corporate client. Each member has:

* A **role type** defining their relationship to the corporate (e.g., OWNER, DIRECTOR, BENEFICIAL\_OWNER)
* **Screening statuses** for Sanctions, PEP, and Adverse Media checks
* An **approval status** reflecting their overall verification state

Members support **upsert** behavior: if a member with the same `referenceId` already exists, it will be updated.

### Available Role Types

| Role                        | Description                               |
| --------------------------- | ----------------------------------------- |
| `OWNER`                     | Owner of the corporate entity             |
| `DIRECTOR`                  | Director / board member                   |
| `OFFICER`                   | Corporate officer                         |
| `AUTHORIZED_REPRESENTATIVE` | Authorized to act on behalf of the entity |
| `BENEFICIAL_OWNER`          | Ultimate beneficial owner (UBO)           |
| `SHAREHOLDER`               | Shareholder of the entity                 |
| `SIGNATORY`                 | Authorized signatory                      |
| `TRUSTEE`                   | Trustee (for trusts)                      |
| `PROTECTOR`                 | Trust protector                           |
| `SETTLOR`                   | Trust settlor                             |
| `OTHER`                     | Other relationship                        |

***

## Step 1: Create Individual Members

**Endpoint:** `POST /v1/members/individuals`

Use this endpoint to add natural persons (e.g., UBOs, directors) to a corporate client.

<CodeGroup>
  ```json REST API theme={null}
  POST /v1/members/individuals?upsert=true
  Content-Type: application/json

  {
    "referenceId": "MEM-IND-001",
    "firstName": "Jane",
    "lastName": "Smith",
    "middleName": "Marie",
    "email": "jane.smith@example.com",
    "phoneNumber": "+1-555-123-4567",
    "dateOfBirth": "1980-03-20T00:00:00Z",
    "citizenship": "USA",
    "personalIdNumber": "987-65-4321",
    "residentialAddressLine1": "456 Oak Avenue",
    "residentialAddressCity": "San Francisco",
    "residentialAddressPostalCode": "94102",
    "residentialAddressCountry": "USA",
    "ownershipPercentage": 35,
    "roleType": "BENEFICIAL_OWNER",
    "title": "Co-Founder",
    "status": "APPROVED",
    "statusDate": "2024-01-10T00:00:00Z",
    "sanctionsStatus": "CLEAR",
    "sanctionsStatusDate": "2024-01-10T00:00:00Z",
    "pepStatus": "CLEAR",
    "pepStatusDate": "2024-01-10T00:00:00Z",
    "adverseMediaStatus": "CLEAR",
    "adverseMediaStatusDate": "2024-01-10T00:00:00Z",
    "corporates": ["corporate-client-uuid"]
  }
  ```

  ```typescript Javascript theme={null}
  const member = await corsa.members.createIndividualMember(
    {
      referenceId: "MEM-IND-001",
      firstName: "Jane",
      lastName: "Smith",
      middleName: "Marie",
      email: "jane.smith@example.com",
      phoneNumber: "+1-555-123-4567",
      dateOfBirth: "1980-03-20T00:00:00Z",
      citizenship: "USA",
      personalIdNumber: "987-65-4321",
      residentialAddressLine1: "456 Oak Avenue",
      residentialAddressCity: "San Francisco",
      residentialAddressPostalCode: "94102",
      residentialAddressCountry: "USA",
      ownershipPercentage: 35,
      roleType: "BENEFICIAL_OWNER",
      title: "Co-Founder",
      status: "APPROVED",
      statusDate: "2024-01-10T00:00:00Z",
      sanctionsStatus: "CLEAR",
      sanctionsStatusDate: "2024-01-10T00:00:00Z",
      pepStatus: "CLEAR",
      pepStatusDate: "2024-01-10T00:00:00Z",
      adverseMediaStatus: "CLEAR",
      adverseMediaStatusDate: "2024-01-10T00:00:00Z",
      corporates: ["corporate-client-uuid"],
    },
    true // upsert
  );
  ```

  ```python Python theme={null}
  from corsa_sdk.api.members.create_individual_member import _get_kwargs
  from corsa_sdk.models.create_individual_member_dto import CreateIndividualMemberDto

  resp = http.request(**_get_kwargs(
      body=CreateIndividualMemberDto(
          reference_id="MEM-IND-001",
          first_name="Jane",
          last_name="Smith",
          middle_name="Marie",
          email="jane.smith@example.com",
          phone_number="+1-555-123-4567",
          date_of_birth="1980-03-20T00:00:00Z",
          citizenship="USA",
          personal_id_number="987-65-4321",
          residential_address_line1="456 Oak Avenue",
          residential_address_city="San Francisco",
          residential_address_postal_code="94102",
          residential_address_country="USA",
          ownership_percentage=35,
          role_type="BENEFICIAL_OWNER",
          title="Co-Founder",
          status="APPROVED",
          status_date="2024-01-10T00:00:00Z",
          sanctions_status="CLEAR",
          sanctions_status_date="2024-01-10T00:00:00Z",
          pep_status="CLEAR",
          pep_status_date="2024-01-10T00:00:00Z",
          adverse_media_status="CLEAR",
          adverse_media_status_date="2024-01-10T00:00:00Z",
          corporates=["corporate-client-uuid"],
      ),
      upsert=True,
  ))
  member = resp.json()
  ```
</CodeGroup>

### Key Fields

| Field                   | Required | Description                                                    |
| ----------------------- | -------- | -------------------------------------------------------------- |
| `firstName`, `lastName` | Yes      | Member's name                                                  |
| `roleType`              | Yes      | Relationship to the corporate (see role types above)           |
| `title`                 | Yes      | Position or title within the organization                      |
| `status`                | Yes      | Verification status: `APPROVED`, `REJECTED`, or `UNDER_REVIEW` |
| `statusDate`            | Yes      | Date of status determination                                   |
| `sanctionsStatus`       | Yes      | `CLEAR`, `FLAGGED`, `UNDER_REVIEW`, or `NOT_CHECKED`           |
| `pepStatus`             | Yes      | PEP screening status (same values as sanctions)                |
| `adverseMediaStatus`    | Yes      | Adverse media screening status (same values as sanctions)      |
| `corporates`            | No       | Array of corporate client IDs to associate this member with    |
| `ownershipPercentage`   | No       | Percentage of ownership (0-100)                                |

You can also include `identityDocuments` inline when creating a member (see Step 2).

***

## Step 2: Add Identity Documents

**Endpoint:** `POST /v1/members/individuals/{memberId}/documents`

After creating a member, you can add identity documents to them.

<CodeGroup>
  ```json REST API theme={null}
  POST /v1/members/individuals/member-uuid/documents
  Content-Type: application/json

  {
    "documentType": "PASSPORT",
    "documentNumber": "AB1234567",
    "documentIssuingCountry": "USA",
    "documentExpirationDate": "2030-06-15",
    "documentImageUrl": "https://your-storage.com/documents/passport-scan.jpg"
  }
  ```

  ```typescript Javascript theme={null}
  const updatedMember = await corsa.members.addIndividualMemberDocument(
    "member-uuid",
    {
      documentType: "PASSPORT",
      documentNumber: "AB1234567",
      documentIssuingCountry: "USA",
      documentExpirationDate: "2030-06-15",
      documentImageUrl: "https://your-storage.com/documents/passport-scan.jpg",
    }
  );
  ```

  ```python Python theme={null}
  from corsa_sdk.api.members.add_individual_member_document import _get_kwargs
  from corsa_sdk.models.create_identity_document_dto import CreateIdentityDocumentDto

  resp = http.request(**_get_kwargs(
      member_id="member-uuid",
      body=CreateIdentityDocumentDto(
          document_type="PASSPORT",
          document_number="AB1234567",
          document_issuing_country="USA",
          document_expiration_date="2030-06-15",
          document_image_url="https://your-storage.com/documents/passport-scan.jpg",
      ),
  ))
  updated_member = resp.json()
  ```
</CodeGroup>

### Supported Document Types

| Type                | Description            |
| ------------------- | ---------------------- |
| `PASSPORT`          | International passport |
| `DRIVERS_LICENSE`   | Driver's license       |
| `NATIONAL_ID`       | National ID card       |
| `RESIDENCE_PERMIT`  | Residence permit       |
| `BIRTH_CERTIFICATE` | Birth certificate      |
| `OTHER`             | Other document type    |

<Note>You can add up to 10 identity documents per member. Documents can also be included inline in the `identityDocuments` array when creating the member in Step 1.</Note>

***

## Step 3: Create Corporate Members

**Endpoint:** `POST /v1/members/corporates`

For nested corporate ownership structures, you can add corporate entities as members of another corporate client.

<CodeGroup>
  ```json REST API theme={null}
  POST /v1/members/corporates?upsert=true
  Content-Type: application/json

  {
    "referenceId": "MEM-CORP-001",
    "legalEntityName": "Acme Holdings Ltd",
    "countryOfIncorporation": "GBR",
    "registrationNumber": "12345678",
    "dateOfIncorporation": "2015-01-01T00:00:00Z",
    "businessAddressLine1": "100 Finance Street",
    "businessAddressCity": "London",
    "businessAddressPostalCode": "EC2R 8AH",
    "businessAddressCountry": "GBR",
    "email": "contact@acmeholdings.com",
    "ownershipPercentage": 51,
    "roleType": "SHAREHOLDER",
    "title": "Parent Company",
    "status": "APPROVED",
    "statusDate": "2024-01-10T00:00:00Z",
    "sanctionsStatus": "CLEAR",
    "sanctionsStatusDate": "2024-01-10T00:00:00Z",
    "pepStatus": "NOT_CHECKED",
    "pepStatusDate": "2024-01-10T00:00:00Z",
    "adverseMediaStatus": "CLEAR",
    "adverseMediaStatusDate": "2024-01-10T00:00:00Z",
    "corporates": ["corporate-client-uuid"]
  }
  ```

  ```typescript Javascript theme={null}
  const corpMember = await corsa.members.createCorporateMember(
    {
      referenceId: "MEM-CORP-001",
      legalEntityName: "Acme Holdings Ltd",
      countryOfIncorporation: "GBR",
      registrationNumber: "12345678",
      dateOfIncorporation: "2015-01-01T00:00:00Z",
      businessAddressLine1: "100 Finance Street",
      businessAddressCity: "London",
      businessAddressPostalCode: "EC2R 8AH",
      businessAddressCountry: "GBR",
      email: "contact@acmeholdings.com",
      ownershipPercentage: 51,
      roleType: "SHAREHOLDER",
      title: "Parent Company",
      status: "APPROVED",
      statusDate: "2024-01-10T00:00:00Z",
      sanctionsStatus: "CLEAR",
      sanctionsStatusDate: "2024-01-10T00:00:00Z",
      pepStatus: "NOT_CHECKED",
      pepStatusDate: "2024-01-10T00:00:00Z",
      adverseMediaStatus: "CLEAR",
      adverseMediaStatusDate: "2024-01-10T00:00:00Z",
      corporates: ["corporate-client-uuid"],
    },
    true // upsert
  );
  ```

  ```python Python theme={null}
  from corsa_sdk.api.members.create_corporate_member import _get_kwargs
  from corsa_sdk.models.create_corporate_member_dto import CreateCorporateMemberDto

  resp = http.request(**_get_kwargs(
      body=CreateCorporateMemberDto(
          reference_id="MEM-CORP-001",
          legal_entity_name="Acme Holdings Ltd",
          country_of_incorporation="GBR",
          registration_number="12345678",
          date_of_incorporation="2015-01-01T00:00:00Z",
          business_address_line1="100 Finance Street",
          business_address_city="London",
          business_address_postal_code="EC2R 8AH",
          business_address_country="GBR",
          email="contact@acmeholdings.com",
          ownership_percentage=51,
          role_type="SHAREHOLDER",
          title="Parent Company",
          status="APPROVED",
          status_date="2024-01-10T00:00:00Z",
          sanctions_status="CLEAR",
          sanctions_status_date="2024-01-10T00:00:00Z",
          pep_status="NOT_CHECKED",
          pep_status_date="2024-01-10T00:00:00Z",
          adverse_media_status="CLEAR",
          adverse_media_status_date="2024-01-10T00:00:00Z",
          corporates=["corporate-client-uuid"],
      ),
      upsert=True,
  ))
  corp_member = resp.json()
  ```
</CodeGroup>

***

## Step 4: Update Members

Use the PUT endpoints to update existing member data as screening results change or information is updated.

### Update an Individual Member

**Endpoint:** `PUT /v1/members/individuals/{memberId}`

<CodeGroup>
  ```json REST API theme={null}
  PUT /v1/members/individuals/member-uuid
  Content-Type: application/json

  {
    "sanctionsStatus": "FLAGGED",
    "sanctionsStatusDate": "2024-06-15T00:00:00Z",
    "status": "UNDER_REVIEW",
    "statusDate": "2024-06-15T00:00:00Z"
  }
  ```

  ```typescript Javascript theme={null}
  const updated = await corsa.members.updateIndividualMember(
    "member-uuid",
    {
      sanctionsStatus: "FLAGGED",
      sanctionsStatusDate: "2024-06-15T00:00:00Z",
      status: "UNDER_REVIEW",
      statusDate: "2024-06-15T00:00:00Z",
    }
  );
  ```

  ```python Python theme={null}
  from corsa_sdk.api.members.update_individual_member import _get_kwargs
  from corsa_sdk.models.update_individual_member_dto import UpdateIndividualMemberDto

  resp = http.request(**_get_kwargs(
      member_id="member-uuid",
      body=UpdateIndividualMemberDto(
          sanctions_status="FLAGGED",
          sanctions_status_date="2024-06-15T00:00:00Z",
          status="UNDER_REVIEW",
          status_date="2024-06-15T00:00:00Z",
      ),
  ))
  updated = resp.json()
  ```
</CodeGroup>

### Update a Corporate Member

**Endpoint:** `PUT /v1/members/corporates/{memberId}`

<CodeGroup>
  ```json REST API theme={null}
  PUT /v1/members/corporates/member-uuid
  Content-Type: application/json

  {
    "ownershipPercentage": 60,
    "adverseMediaStatus": "FLAGGED",
    "adverseMediaStatusDate": "2024-06-15T00:00:00Z"
  }
  ```

  ```typescript Javascript theme={null}
  const updated = await corsa.members.updateCorporateMember(
    "member-uuid",
    {
      ownershipPercentage: 60,
      adverseMediaStatus: "FLAGGED",
      adverseMediaStatusDate: "2024-06-15T00:00:00Z",
    }
  );
  ```

  ```python Python theme={null}
  from corsa_sdk.api.members.update_corporate_member import _get_kwargs
  from corsa_sdk.models.update_corporate_member_dto import UpdateCorporateMemberDto

  resp = http.request(**_get_kwargs(
      member_id="member-uuid",
      body=UpdateCorporateMemberDto(
          ownership_percentage=60,
          adverse_media_status="FLAGGED",
          adverse_media_status_date="2024-06-15T00:00:00Z",
      ),
  ))
  updated = resp.json()
  ```
</CodeGroup>

All fields are optional on update - only include the fields you want to change.

***

## What's Next?

<CardGroup cols={2}>
  <Card title="Accounts & Wallets" icon="building-columns" href="/api/ingesting-accounts-and-wallets">
    Ingest bank accounts and blockchain wallets for your clients.
  </Card>

  <Card title="Ingest Operations" icon="arrow-right-arrow-left" href="/api/ingesting-operations">
    Ingest deposits, withdrawals, and trades.
  </Card>
</CardGroup>
