Identity Verification (KYC)

Requirements

In order to comply with international and domestic regulations, all entities require identity verification (KYC). This can be done in a couple ways, via Partner KYC (also known as KYC reliance) and Managed KYC (Dinari-managed).

Integration Types

Partner KYC

If you already collect and verify KYC information from your users, you may submit their KYC data to the Dinari API for a completely transparent experience for your customers.

Requirements:

  • Use a supported KYC provider
  • Submit all the required KYC fields to the Dinari KYC API.
  • Submit a copy of your AML program
⚠️

KYC Policy and Process Audits

Dinari may periodically request to audit your KYC policies and processes. Dinari will periodically verify the data sent to us.

To enable Partner KYC, please reach out to [email protected].

Managed KYC

If you do not currently collect or verify KYC information, Dinari provides a whitelabel solution that you can offer to your users.

  1. Use the Create Managed KYC Check endpoint to generate a unique KYC URL.
  2. Present this URL to a user in your application.
  3. The user then follows this link and is presented with web embedded KYC flow with our identity verification partner compatible on both mobile and desktop experiences.
  4. Once they complete this flow, the user's identity is verified in realtime and will then be able to place trades.

Additional fees may apply.

Supported Identity Verification Providers

The following identity verification providers have been approved for use. If you use one that is not on this list, please let us know!

⚠️ Special Jurisdictions

  • US - Additional requirements apply. See the US Integration Guide (coming Q4 2025).

Integration

The following section details how you can manage this information. Please note that for your organization's Entity, the requirement is to be KYB'ed.

SDK Reference

SDK Examples

Partner-Managed KYC

import Dinari from '@dinari/api-sdk';

const client = new Dinari({
  apiKeyID: process.env['DINARI_API_KEY_ID'], // This is the default and can be omitted
  apiSecretKey: process.env['DINARI_API_SECRET_KEY'], // This is the default and can be omitted
  environment: 'sandbox', // defaults to 'production'
});

async function main() {
  const entity = await client.v2.entities.create({
    name: 'Jane Doe',
  });

  const kyc = await client.v2.entities.kyc.submit(entity.id, {
    data: {
      country_code: 'US',
      first_name: 'Jane',
      middle_name: 'Marie',
      last_name: 'Doe',
      birth_date: '1990-01-01',
      email: '[email protected]',
      tax_id_number: '123-45-6789',
      address_street_1: '123 Main St',
      address_street_2: 'Apt 4B',
      address_city: 'New York',
      address_subdivision: 'New York',
      address_postal_code: '10001',
    },
    provider_name: '',
  });

  const file = new Blob(['...binary content...'], { type: 'image/jpeg' }); // Replace with actual file upload logic

  const uploadResponse = await client.v2.entities.kyc.document.upload(kyc.id, {
    entity_id: entity.id,
    document_type: 'GOVERNMENT_ID', // Use appropriate enum or value from SDK
    file,
  });

  console.log(uploadResponse);
}

main();
import os
from dinari_api_sdk import Dinari

client = Dinari(
    api_key_id=os.environ.get("DINARI_API_KEY_ID"),  # This is the default and can be omitted
    api_secret_key=os.environ.get("DINARI_API_SECRET_KEY"),  # This is the default and can be omitted
    environment="sandbox", # defaults to "production"
)

entity = client.v2.entities.create(
    name="Jane Doe",
)

kyc = client.v2.entities.kyc.submit(
    entity_id=entity.id,
    data={
        "country_code": "US",
        "first_name": "Jane",
        "middle_name": "Marie",
        "last_name": "Doe",
        "birth_date": "1990-01-01",
        "email": "[email protected]",
        "tax_id_number": "123-45-6789",
        "address_street_1": "123 Main St",
        "address_street_2": "Apt 4B",
        "address_city": "New York",
        "address_subdivision": "New York",
        "address_postal_code": "10001",
    },
    provider_name="",
)

with open("./gov-id.jpeg", "rb") as f:
    upload_response = client.v2.entities.kyc.document.upload(
        kyc_id=kyc.id,
        entity_id=entity.id,
        document_type="GOVERNMENT_ID",
        file=f,
    )
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"time"

	dinari "github.com/dinaricrypto/dinari-api-sdk-go"
	"github.com/dinaricrypto/dinari-api-sdk-go/option"
)

func main() {
	// DINARI_API_KEY_ID and DINARI_API_SECRET_KEY are set as environment variables
	client := dinari.NewClient(
		option.WithEnvironmentSandbox(), // Defaults to production when omitted
	)

	newEntity, err := client.V2.Entities.New(context.TODO(), dinari.V2EntityNewParams{
		Name: "Jane Doe",
	})
	if err != nil {
		log.Fatalf("Failed to create entity: %v", err)
	}

	kycSubmitBody := dinari.V2EntityKYCSubmitParams{
		Data: dinari.KYCDataParam{
			CountryCode:        "US",
			LastName:           "Doe",
			AddressCity:        dinari.String("New York"),
			AddressPostalCode:  dinari.String("10001"),
			AddressStreet1:     dinari.String("123 Main St"),
			AddressStreet2:     dinari.String("Apt 4B"),
			AddressSubdivision: dinari.String("New York"),
			BirthDate:          dinari.Time(time.Date(1990, 1, 1, 0, 0, 0, 0, time.UTC)),
			Email:              dinari.String("[email protected]"),
			FirstName:          dinari.String("Jane"),
			MiddleName:         dinari.String("Marie"),
			TaxIDNumber:        dinari.String("123-45-6789"),
		},
		ProviderName: "",
	}

	kycInfo, err := client.V2.Entities.KYC.Submit(context.TODO(), newEntity.ID, kycSubmitBody)
	if err != nil {
		log.Fatalf("Failed to submit KYC data: %v", err)
	}

	file, err := os.Open("path/to/document.jpg")
	if err != nil {
		log.Fatalf("Failed to open file: %v", err)
	}
	defer file.Close()

	kycParams := dinari.V2EntityKYCDocumentUploadParams{
		EntityID:     newEntity.ID,
		DocumentType: dinari.KYCDocumentTypeGovernmentID,
		File:         file,
	}

	uploadResp, err := client.V2.Entities.KYC.Document.Upload(context.TODO(), kycInfo.ID, kycParams)
	if err != nil {
		log.Fatalf("Failed to upload KYC document: %v", err)
	}

	fmt.Printf("Document upload response: %+v\\n", uploadResp)
}

White-labeled KYC

import Dinari from '@dinari/api-sdk';

const client = new Dinari({
  apiKeyID: process.env['DINARI_API_KEY_ID'], // This is the default and can be omitted
  apiSecretKey: process.env['DINARI_API_SECRET_KEY'], // This is the default and can be omitted
  environment: 'sandbox', // defaults to 'production'
});

async function main() {
  const entityID = '0197423b-d4f9-7cdc-80e4-d50814958e44'; // Replace with your actual entity ID

  const kycResponse = await client.v2.entities.kyc.createManagedCheck(entityID);

  console.log(kycResponse.embed_url);
}

main();
import os
from dinari_api_sdk import Dinari

client = Dinari(
    api_key_id=os.environ.get("DINARI_API_KEY_ID"),  # This is the default and can be omitted
    api_secret_key=os.environ.get("DINARI_API_SECRET_KEY"),  # This is the default and can be omitted
    environment="sandbox", # defaults to "production"
)

entity = client.v2.entities.create(
    name="Jane Doe",
)

redirect = client.v2.entities.kyc.create_managed_check(
    entity_id=entity.id,
)

print("Redirect user to:", redirect.embed_url)
package main

import (
	"context"
	"fmt"
	"log"

	dinari "github.com/dinaricrypto/dinari-api-sdk-go"
	"github.com/dinaricrypto/dinari-api-sdk-go/option"
)

func main() {
	// DINARI_API_KEY_ID and DINARI_API_SECRET_KEY are set as environment variables
	client := dinari.NewClient(
		option.WithEnvironmentSandbox(), // Defaults to production when omitted
	)

	entityID := "0197423b-d4f9-7cdc-80e4-d50814958e44"

	kycResp, err := client.V2.Entities.KYC.NewManagedCheck(context.TODO(), entityID)
	if err != nil {
		log.Fatalf("Failed to initiate managed KYC check: %v", err)
	}

	fmt.Printf("KYC Redirect URL: %s\n", kycResp.EmbedURL)
}