> 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/add-kyc-certificate.md).

# Add KYC Certificate

This guide shows the steps needed to obtain and add a KYC certificate to an account. It uses the Footprint sandbox anchor for demonstration purposes and the Anchor Resolver to search for the provider.

{% stepper %}
{% step %}

### Prepare your account

Generate the account to add the certificate to

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

```ts
import * as KeetaAnchor from "@keetanetwork/anchor";
const userAccount = Account.fromSeed(seed, 0);
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-expandable="true"><code class="lang-csharp"><strong>using KeetaNet.Anchor;
</strong>using Account userAccount = runtime.Accounts.FromSeed(seed, 0, "ecdsa_secp256k1");w
</code></pre>

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

{% step %}

### Create a UserClient

A UserClient is used to interact with Keeta

{% tabs %}
{% tab title="Typescript" %}

```typescript
await using userClient = KeetaAnchor.KeetaNet.UserClient.fromNetwork(
  network,
	userAccount
);
```

{% endtab %}

{% tab title="C#" %}

```csharp
using UserClient userClient = UserClient.FromNetwork(Network, userAccount);
```

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

{% step %}

### Create an Anchor KYC Client

Anchor clients use a UserClient and add Anchor specific interactions like KYC, FX and Asset Movement

{% tabs %}
{% tab title="Typescript" %}

```typescript
const kycClient = new KeetaAnchor.KYC.Client(userClient);
```

{% endtab %}

{% tab title="C#" %}

```csharp
using KycClient kycClient = runtime.CreateKycClient(
			TestnetEndpoints.NodeApi,
			userClient.NetworkAddress,
			userAccount);
```

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

{% step %}

### Get available providers

This will search the Anchor Registry for KYC Anchors that support the provided details (eg. US country code in this example)

{% tabs %}
{% tab title="Typescript" %}

```typescript
const providers = await kycClient.createVerification({
  countryCodes: ['US'],
	account: userAccount
});
```

{% endtab %}

{% tab title="C#" %}

```csharp
IReadOnlyList<KycProvider> providers = await kycClient.GetProviders(Countries, cancellationToken);
```

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

{% step %}

### Start the KYC Verification

We'll use the provider matching the "Footprint" id in this step. Sandbox has 2 providers, a basic demo provider as well as the Footprint provider. Then start the verification. The result of starting verification returns a webURL that can be used to complete the KYC Verification with the KYC Anchor.

{% tabs %}
{% tab title="Typescript" %}

```typescript
const provider = providers.find((p) => p.id === "Footprint");
const verification = await provider.startVerification();

console.log(verification.webURL);
```

{% endtab %}

{% tab title="C#" %}

```csharp
KycProvider? provider = providers.FirstOrDefault(candidate => candidate.Id == "Footprint");

VerificationOutcome created = await kycClient.StartVerification(provider, Countries, cancellationToken: cancellationToken);
if (created.Ready is null) {
  Verification verification = created.Ready;
  Console.WriteLine(verification.WebUrl);
}
```

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

{% step %}

### Get KYC Certificate from Provider

Once the KYC Verification is complete, we can obtain the KYC Certificate from the Anchor.

{% tabs %}
{% tab title="Typescript" %}

```typescript
const certificates = await verification.getCertificates();
```

{% endtab %}

{% tab title="C#" %}

```csharp
CertificatesOutcome results = await kycClient.GetCertificates(provider, verification.Id, cancellationToken);
```

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

{% step %}

### Add KYC Certificate to User Account

The KYC Anchor returns the leaf certificate and intermediates that can be used to construct the chain of authority. We can then add the certificates to the account. If the Anchor returns multiple certificates we can iterate through all of them.

{% tabs %}
{% tab title="Typescript" %}

```typescript
for (const [i, certGroup] of certificates.results.entries()) {
  // Re-wrap with the user's account as the subject key so sensitive
	// attributes (PII) can be decrypted
	const cert = new KeetaAnchor.lib.Certificates.Certificate(
		certGroup.certificate.toPEM(),
		{ subjectKey: userAccount }
	);

	// Construct the Certificate Bundle from Intermediates
	const intermediates = certGroup.intermediates
	  ? new KeetaAnchor.KeetaNet.lib.Utils.Certificate.CertificateBundle([...certGroup.intermediates])
		: null;
			
	// Attach the certificate to the user's account onchain
	await userClient.modifyCertificate(
	  KeetaAnchor.KeetaNet.lib.Block.AdjustMethod.ADD,
		cert,
		intermediates
	);
}
```

{% endtab %}

{% tab title="C#" %}

```csharp
foreach (IssuedCertificate issued in results.Ready.Results)
{
  index++;
	using KycCertificate certificate = runtime.KycCertificates.Parse(issued.Value);
	Console.WriteLine($"\n  Certificate {index}:");
	using CryptoCertificate baseCertificate = certificate.Base();
	Console.WriteLine($"    Subject: {baseCertificate.Subject}");
	Console.WriteLine($"    Valid: {certificate.IsValidAt(DateTimeOffset.UtcNow)}");

	if (issued.Intermediates.Count > 0)
	{
		Console.WriteLine($"    Intermediate certificates: {issued.Intermediates.Count}");
	}

	if (certificate.GetAttributeNames().Contains("fullName", StringComparer.Ordinal))
	{
		KycAttributeValue fullName = certificate.GetAttribute("fullName", userAccount);
		Console.WriteLine($"    Full name (decrypted): {fullName.AsText()}");
	}

	await userClient.ModifyCertificateAsync(
		runtime,
		issued.Value,
		issued.Intermediates,
		cancellationToken: cancellationToken).ConfigureAwait(false);
}
```

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

{% step %}

### Read Certificates from User Account

{% tabs %}
{% tab title="Typescript" %}

```typescript
const onChain = await userClient.client.getAllCertificates(userAccount);
console.log(`\nOn-chain certificates for this account: ${onChain.length}`);
```

{% endtab %}

{% tab title="C#" %}

```csharp
IReadOnlyList<IssuedCertificate> onChain = await nodeClient.GetAllCertificates(userAccount, cancellationToken);
Console.WriteLine($"\nOn-chain certificates for this account: {onChain.Count}");
```

{% 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.ts>" %}
{% endtab %}

{% tab title="C#" %}
{% @github-files/github-code-block url="<https://github.com/KeetaNetwork/keetanet-examples/blob/main/csharp/src/Anchor/KycClient.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/add-kyc-certificate.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.
