> For the complete documentation index, see [llms.txt](https://docs.keeta.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.keeta.com/guides/share-kyc-attributes.md).

# Share KYC Attributes

This guide shows how to use the Anchor SDK to share KYC attributes with an Anchor that requires KYC using an existing on-chain KYC certificate.

{% stepper %}
{% step %}

### Identify Share KYC Is Required

When an Anchor requires KYC it will return an error of type `KeetaAssetMovementAnchorKYCShareNeededError`  and will include the required KYC attributes and which Keeta account they should be shared with.  Sharing KYC attributes uses encrypted containers that only grant the specific principals access to decrypt the container so it remains encrypted in transit.\
`KeetaAssetMovementAnchorKYCShareNeededError` members shown below.

{% tabs %}
{% tab title="TypeScript" %}
{% code expandable="true" %}

```ts
    readonly shareWithPrincipals: Account[];
    readonly neededAttributes: string[] | undefined;
    readonly tosFlow: KeetaAssetMovementAnchorKYCExternalURLFlow | undefined;
    readonly acceptedIssuers: {
        name: string;
        value: string;
    }[][];
```

{% endcode %}
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Select KYC Certificate

Full example below shows more in depth details on identifying a KYC certificate on the users account, for example an Anchor may require a certificate from a specific issuer. At a high level it follows these steps to get the certificates for the account from the network and build the Certificate.

{% tabs %}
{% tab title="TypeScript" %}
{% code expandable="true" %}

```ts
// Get account certificates
const records = await userClient.client.getAllCertificates(account);

// Build the intermediates from the first result
const intermediateSet = records[0].intermediates
	? new Set(records[0].intermediates.getCertificates())
	: undefined;

// Construct the certificate from the first result
const certificate = new KeetaAnchor.lib.Certificates.Certificate(records[0].certificate.toPEM(), {
	subjectKey: userAccount,
	store: {
		root: trustedRoots,
		intermediate: intermediateSet ?? new Set()
	}
});
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}
{% code expandable="true" %}

```csharp
IReadOnlyList<OnChainCertificate> records = await nodeClient.GetAllCertificates(userAccount, cancellationToken);

const intermediateSet = record.intermediates
  ? new Set(record.intermediates.getCertificates())
	: undefined;

if (trustedRoots.size > 0) {
	const cert = new KeetaAnchor.lib.Certificates.Certificate(record.certificate.toPEM(), {
		subjectKey: account,
		store: {
			root: trustedRoots,
			intermediate: intermediateSet ?? new Set()
		}
	});
}
```

{% endcode %}
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Build the Sharable Certificate Attributes

Create the encrypted container to share certificate attributes, this selects only the attributes requested by the Anchor.

{% tabs %}
{% tab title="TypeScript" %}
{% code expandable="true" %}

```ts
const sharable = await KeetaAnchor.lib.Certificates.SharableCertificateAttributes.fromCertificate(
  certificate,
  intermediateSet,
	neededAttributes
);
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}
{% code expandable="true" %}

```csharp
SharableCertificateAttributes sharable = await runtime.Sharables.FromCertificate(
  certificate,
  userAccount,
  httpClient,
	intermediates,
	neededAttributes,
	cancellationToken);
```

{% endcode %}
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Grant Access for the Anchor

Granting access to the encrypted container allows the principal to decrypt the attributes.  This enables the sensitive attributes to be encrypted in transit and only viewable by the recipient.

{% tabs %}
{% tab title="TypeScript" %}
{% code expandable="true" %}

```ts
for (const principal of shareWithPrincipals) {
  await sharable.grantAccess(principal);
}
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}
{% code expandable="true" %}

```csharp
foreach (string principalAddress in shareWithPrincipals)
{
  using Account principal = runtime.Accounts.FromPublicKeyString(principalAddress);
  sharable.GrantAccess([principal]);
}
```

{% endcode %}
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Share the Attributes with the Anchor

Anchor providers that require KYC have an endpoint to share the attributes.  The Anchor Client SDK handles the request details.

{% tabs %}
{% tab title="TypeScript" %}
{% code expandable="true" %}

```ts
await provider.shareKYCAttributes({
  account,
	attributes: sharable
});
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}
{% code expandable="true" %}

```csharp
await assetMovementClient.ShareKycAttributesAndWait(
  provider,
	new AssetShareKycRequest(sharable.ToPem()),
	cancellationToken: cancellationToken);
```

{% endcode %}
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Handle Additional Onboarding Steps

An Anchor may require some additional onboarding steps.  Like adding it's own certificate to the account or granting permissions. These will be identified with an error of type `KeetaAssetMovementAnchorUserActionNeededError`

The `actionsNeeded` attribute of the error can be used to complete the actions and the UserClientBuilder can be used to construct a Keeta block to publish the actions.

{% tabs %}
{% tab title="TypeScript" %}
{% code expandable="true" %}

```ts
const builder = userClient.initBuilder();
KeetaAssetMovementAnchorUserActionNeededError.addOperationsToBuilder(actionsNeeded, builder);
await userClient.publishBuilder(builder);
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}
{% code expandable="true" %}

```csharp
// C#: translate the required actions into ledger operations and publish them in one block.
await UserActions.Execute(runtime, userClient, userActionNeeded, cancellationToken);
```

{% endcode %}
{% endtab %}
{% endtabs %}
{% endstep %}
{% endstepper %}

## Full Code Example

{% tabs %}
{% tab title="TypeScript" %}
{% @github-files/github-code-block url="<https://github.com/KeetaNetwork/keetanet-examples/blob/main/src/anchor/kyc-client-sharekyc.ts>" %}
{% endtab %}

{% tab title="C#" %}
{% @github-files/github-code-block url="<https://github.com/KeetaNetwork/keetanet-examples/blob/main/csharp/src/Anchor/KycClientShareKyc.cs>" %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.keeta.com/guides/share-kyc-attributes.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
