Skip to main content
Before processing payments, customers must complete KYB (Know Your Business) onboarding. This guide explains how to integrate Dakota Platform’s onboarding flow.

Overview

The onboarding process involves:
  1. Creating a customer record (KYB automatically initiated)
  2. Redirecting customer to complete verification
  3. Monitoring KYB status via API or webhooks

Step 1: Create a Customer

First, create a customer record with basic business information.

Customer Creation Fields

FieldTypeRequiredDescriptionExample
namestringLegal name of the business or individual"Acme Corp"
customer_typestringType of customer account. Must be "business" or "individual""business"
external_idstringYour internal identifier for this customer"acme_001"

Request Example

cURL
curl -X POST https://api.platform.dakota.xyz/customers \
  -H "X-API-Key: your-api-key" \
  -H "X-Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp",
    "customer_type": "business"
  }'
JavaScript
const response = await fetch('https://api.platform.dakota.xyz/customers', {
  method: 'POST',
  headers: {
    'X-API-Key': 'your-api-key',
    'X-Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Acme Corp',
    customer_type: 'business'
  })
});

const customer = await response.json();
console.log('Created customer:', customer.data.id);
Python
import requests
import uuid

response = requests.post(
    'https://api.platform.dakota.xyz/customers',
    headers={
        'X-API-Key': 'your-api-key',
        'X-Idempotency-Key': str(uuid.uuid4()),
        'Content-Type': 'application/json'
    },
    json={
        'name': 'Acme Corp',
        'customer_type': 'business'
    }
)

customer = response.json()
print(f'Created customer: {customer["data"]["id"]}')
Go
package main

import (
    "bytes"
    "net/http"
    "github.com/google/uuid"
)

func main() {
    client := &http.Client{}
    body := bytes.NewBufferString(`{
        "name": "Acme Corp",
        "customer_type": "business"
    }`)
    
    req, _ := http.NewRequest("POST", "https://api.platform.dakota.xyz/customers", body)
    
    req.Header.Add("X-API-Key", "your-api-key")
    req.Header.Add("X-Idempotency-Key", uuid.New().String())
    req.Header.Add("Content-Type", "application/json")
    
    resp, _ := client.Do(req)
    defer resp.Body.Close()
}
Rust
use reqwest::header::{HeaderMap, HeaderValue};
use uuid::Uuid;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    
    let mut headers = HeaderMap::new();
    headers.insert("X-API-Key", HeaderValue::from_static("your-api-key"));
    headers.insert("X-Idempotency-Key", HeaderValue::from_str(&Uuid::new_v4().to_string())?);
    headers.insert("Content-Type", HeaderValue::from_static("application/json"));
    
    let body = json!({
        "name": "Acme Corp",
        "customer_type": "business"
    });
    
    let response = client
        .post("https://api.platform.dakota.xyz/customers")
        .headers(headers)
        .json(&body)
        .send()
        .await?;
    
    Ok(())
}
Java
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.util.UUID;

public class DakotaCustomerExample {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        
        String body = """
            {
              "name": "Acme Corp",
              "customer_type": "business"
            }
            """;
        
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.platform.dakota.xyz/customers"))
            .header("X-API-Key", "your-api-key")
            .header("X-Idempotency-Key", UUID.randomUUID().toString())
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(body))
            .build();
            
        HttpResponse<String> response = client.send(request, 
            HttpResponse.BodyHandlers.ofString());
    }
}
Response:
{
  "data": {
    "id": "2Nq8G7xK9mR4Ls6DyJ1Uf3Tp",
    "name": "Acme Corp",
    "customer_type": "business",
    "external_id": null,
    "kyb_status": "pending",
    "kyb_links": [
      {
        "provider_id": "dakota",
        "link_type": "kyb_onboarding",
        "url": "https://withpersona.com/verify?inquiry-id=inq_abc123456789",
        "status": "pending",
        "created_at": 1705320600,
        "updated_at": 1705320600
      },
      {
        "provider_id": "bridge",
        "link_type": "tos",
        "url": "https://dashboard.bridge.xyz/accept-terms-of-service?redirect_uri=https%3A%2F%2Fapi.platform.dakota.xyz%2Fcustomers%2Fbridge%2Faccepted-tos%3Ftos_id%3D30yRrO1wNMuzUri3BAdhKBiMM09&session_token=56e52844-bbce-402b-a66e-7b97f6d02967",
        "status": "pending",
        "created_at": 1705320600,
        "updated_at": 1705320600
      }
    ],
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-01-15T10:30:00Z"
  }
}

Step 2: KYB Process (Automatic)

The KYB onboarding process is automatically initiated when you create a customer. You don’t need to make additional API calls to start KYB verification.

Automatic KYB Initiation

When you create a customer, the system automatically:
  • Generates a KYB onboarding link with Persona (our default provider)
  • Returns the onboarding URL in the kyb_links array
  • Sets the initial KYB status to "pending"

KYB Response Details

The customer creation response includes:
FieldDescriptionExample
kyb_linksArray of KYB provider information and onboarding linksSee below
kyb_statusCurrent verification status"pending"
Each item in the kyb_links array contains:
FieldDescriptionExample
provider_idKYB provider name"dakota"
link_typeType of KYB link"kyb_onboarding"
urlOnboarding URL for customer"https://withpersona.com/verify?inquiry-id=inq_abc123"
statusLink status"pending"
created_atLink creation timestamp1705320600
updated_atLink last updated timestamp1705320600
From the customer creation response, extract the onboarding URL:
const customer = await response.json();
const kybLink = customer.data.kyb_links[0];
const onboardingUrl = kybLink.url;

// Redirect customer to complete KYB verification
window.location.href = onboardingUrl;

Step 3: Handle the Onboarding Flow

Direct your customer to the onboarding URL (from the kyb_links array) to complete verification. The customer will:
  1. Provide business documentation
  2. Verify business identity
  3. Complete compliance checks
  4. Receive approval or additional requirements

Step 4: Monitor KYB Status

Check onboarding status programmatically:
cURL
curl -X GET https://api.platform.dakota.xyz/customers/{customer_id} \
  -H "X-API-Key: your-api-key"
JavaScript
const response = await fetch(`https://api.platform.dakota.xyz/customers/${customerId}`, {
  headers: {
    'X-API-Key': 'your-api-key'
  }
});

const customer = await response.json();
console.log('KYB Status:', customer.data.kyb_status);
Python
import requests

response = requests.get(
    f'https://api.platform.dakota.xyz/customers/{customer_id}',
    headers={'X-API-Key': 'your-api-key'}
)

customer = response.json()
print(f'KYB Status: {customer["data"]["kyb_status"]}')
Go
package main

import (
    "net/http"
)

func main() {
    client := &http.Client{}
    req, _ := http.NewRequest("GET", "https://api.platform.dakota.xyz/customers/" + customerId, nil)
    
    req.Header.Add("X-API-Key", "your-api-key")
    
    resp, _ := client.Do(req)
    defer resp.Body.Close()
}
Rust
use reqwest::header::{HeaderMap, HeaderValue};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    
    let mut headers = HeaderMap::new();
    headers.insert("X-API-Key", HeaderValue::from_static("your-api-key"));
    
    let response = client
        .get(&format!("https://api.platform.dakota.xyz/customers/{}", customer_id))
        .headers(headers)
        .send()
        .await?;
    
    Ok(())
}
Java
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;

public class DakotaKYBStatusExample {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.platform.dakota.xyz/customers/" + customerId))
            .header("X-API-Key", "your-api-key")
            .GET()
            .build();
            
        HttpResponse<String> response = client.send(request, 
            HttpResponse.BodyHandlers.ofString());
    }
}
Response:
{
  "data": {
    "id": "2Nq8G7xK9mR4Ls6DyJ1Uf3Tp",
    "name": "Acme Corp",
    "customer_type": "business",
    "external_id": null,
    "kyb_status": "approved",
    "kyb_links": [
      {
        "provider_id": "dakota",
        "link_type": "kyb_onboarding",
        "url": "https://withpersona.com/verify?inquiry-id=inq_abc123456789",
        "status": "completed",
        "created_at": 1705320600,
        "updated_at": 1705324200
      },
      {
        "provider_id": "bridge",
        "link_type": "tos",
        "url": "https://dashboard.bridge.xyz/accept-terms-of-service?redirect_uri=https%3A%2F%2Fapi.platform.dakota.xyz%2Fcustomers%2Fbridge%2Faccepted-tos%3Ftos_id%3D30yRrO1wNMuzUri3BAdhKBiMM09&session_token=56e52844-bbce-402b-a66e-7b97f6d02967",
        "status": "completed",
        "created_at": 1705320600,
        "updated_at": 1705322400
      }
    ],
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-01-15T11:45:00Z"
  }
}

KYB Status Values

StatusDescription
not_startedOnboarding not yet started
in_progressCustomer is completing verification
in_reviewProvider is reviewing submission
approvedVerification successful
rejectedVerification failed
requires_infoAdditional information needed
frozenAccount suspended or frozen

Best Practices

User Experience

  • Clearly communicate the onboarding requirements
  • Provide progress indicators
  • Set expectations for processing time
  • Offer support contact information

Error Handling

  • Handle rejection gracefully
  • Provide clear next steps
  • Allow customers to restart if needed
  • Log all onboarding events

Compliance

  • Store audit trails
  • Monitor for suspicious activity
  • Keep records for compliance reporting
  • Regular review of rejected applications

Required Documents

Typical documents required for business verification:
  • Certificate of Incorporation
  • Bank Statements
  • Director/Officer Identification
  • Beneficial Ownership Information

Troubleshooting

Common Issues

Onboarding Stuck in “Pending”
  • Check if customer has accessed the onboarding URL
Repeated Rejections
  • Ensure document quality meets requirements
  • Consider manual review process
Webhook Not Received
  • Verify webhook endpoint is responding with 200
  • Check webhook signature validation
  • Review webhook logs in dashboard
Any issues not covered here can be addressed by contacting Dakota Platform support.

Next Steps

After successful customer onboarding:
  1. Set up Recipients & Destinations - Configure payment targets
  2. Create Transactions - Process payments for approved customers
  3. Webhook Integration - Get real-time KYB status updates
  4. Testing - Test your onboarding flow

API Reference

For detailed endpoint documentation, see: