# Dakota Dakota is a regulated stablecoin infrastructure platform that enables fintechs and enterprises to embed programmable global money movement through APIs. ## Quick Start To make API requests to Dakota, you need an API key and the correct base URL. ### API Base URLs | Environment | API Base URL | Dashboard URL | |-------------|--------------|---------------| | Sandbox | `https://api.platform.sandbox.dakota.xyz` | `https://platform.sandbox.dakota.xyz` | | Production | `https://api.platform.dakota.xyz` | `https://platform.dakota.xyz` | **Recommendation**: Start with the Sandbox environment for development and testing. ### Getting an API Key 1. **Get Dashboard Access**: Contact [Dakota sales](https://dakota.io/talk-to-sales) to set up an account 2. **Log into the Dashboard**: Go to the appropriate dashboard URL above 3. **Create an API Key**: Navigate to **API Keys** section and click **Create New API Key** 4. **Store Securely**: Copy the key immediately (it's only shown once) ### Making Your First Request ```bash curl -X GET https://api.platform.sandbox.dakota.xyz/customers \ -H "x-api-key: YOUR_API_KEY" ``` ### Required Headers | Header | Required For | Description | |--------|--------------|-------------| | `X-API-Key` | All requests | Your API key for authentication | | `X-Idempotency-Key` | **All POST requests** | UUID to prevent duplicate operations. **Required.** | | `Content-Type` | Requests with body | Set to `application/json` | **IMPORTANT: All POST requests MUST include `X-Idempotency-Key` header with a UUID value. Requests without this header will fail.** Example POST request with all required headers: ```bash curl -X POST https://api.platform.dakota.xyz/customers \ -H "X-API-Key: your-api-key" \ -H "X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \ -H "Content-Type: application/json" \ -d '{"name": "Acme Corp", "customer_type": "business"}' ``` --- ## CRITICAL: Prerequisites and Dependencies Before calling Dakota APIs, understand these **mandatory requirements**: | To Create | You Must First Have | |-----------|---------------------| | Recipient | Customer with `kyb_status: "approved"` | | Destination | Recipient | | Onramp Account | Crypto Destination + Customer with `kyb_status: "approved"` | | Offramp Account | Bank Destination + Customer with `kyb_status: "approved"` | | Wallet | Signer Group | | Signer Group | ES256 public keys (ECDSA P-256, SPKI format, base64 encoded) | **KYB Approval Required**: Customers must have `kyb_status: "approved"` before creating onramp/offramp accounts or processing transactions. --- ## Validation Rules | Field | Constraint | |-------|------------| | `customer.name` | 3-100 characters, unique per client | | `recipient.name` | Unique per customer | | `recipient.address` | Requires `street1`, `city`, `country` (ISO 3166-1 alpha-2) | --- ## CRITICAL: ID Types Are NOT Interchangeable Dakota uses different ID types. Using the wrong ID type causes errors: | ID Type | Source Endpoint | Used For | Common Error When Misused | |---------|-----------------|----------|---------------------------| | `wallet_id` | `POST /wallets` | Balance queries only | `destination_not_found` | | `destination_id` | `POST /recipients/{id}/destinations` | Onramp, offramp, transactions | N/A | | `recipient_id` | `POST /customers/{id}/recipients` | Creating destinations | N/A | | `customer_id` | `POST /customers` | All customer operations | N/A | | `signer_group_id` | `POST /signer-groups` | Creating wallets | N/A | **Key Point**: For onramp/offramp, you need a `destination_id` NOT a `wallet_id`. --- ## Complete Flow: Onramp (Fiat to Crypto) ### Step 1: Ensure Customer is KYB Approved ```bash GET /customers/{customer_id} # Must have "kyb_status": "approved" ``` ### Step 2: Create a Recipient ```bash POST /customers/{customer_id}/recipients { "name": "Company Treasury", "address": { "street1": "123 Main St", "city": "San Francisco", "region": "CA", "postal_code": "94102", "country": "US" } } # Returns recipient_id ``` ### Step 3: Create a Crypto Destination ```bash POST /recipients/{recipient_id}/destinations { "destination_type": "crypto", "name": "USDC Wallet", "crypto_address": "0x742d35Cc6634C0532925a3b8D404fA40b5398Ad2", "network_id": "ethereum-mainnet" } # Returns destination_id - USE THIS for onramp ``` ### Step 4: Create Onramp Account ```bash POST /accounts/onramp { "destination_id": "THE_DESTINATION_ID_FROM_STEP_3", "source_asset": "USD", "destination_asset": "USDC", "capabilities": ["ach"] } ``` --- ## Complete Flow: Creating a Wallet Wallets require signer groups. The `signer_groups` field takes an array of **STRING IDs**. ### Public Key Format for member_keys The `member_keys` array requires **ECDSA P-256 (ES256) public keys**: - **Algorithm**: ECDSA with P-256 curve (secp256r1) - **Format**: PKIX/SPKI DER format, Base64 encoded - **Key Type**: ES256 **Generate ES256 key (Node.js):** ```javascript const crypto = require('crypto'); const { publicKey, privateKey } = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }); const publicKeyBase64 = publicKey.export({ type: 'spki', format: 'der' }).toString('base64'); // Use publicKeyBase64 as member_key ``` **Generate ES256 key (Python):** ```python from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import serialization import base64 private_key = ec.generate_private_key(ec.SECP256R1()) public_key_der = private_key.public_key().public_bytes( encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo ) public_key_base64 = base64.b64encode(public_key_der).decode('utf-8') # Use public_key_base64 as member_key ``` ### Step 1: Create a Signer Group ```bash POST /signer-groups { "name": "Treasury Team", "member_keys": ["MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...base64..."] } # Returns signer_group_id ``` ### Step 2: Create Wallet ```bash POST /wallets { "name": "Main Wallet", "family": "evm", "signer_groups": ["THE_SIGNER_GROUP_ID"], "policies": [] } ``` **CORRECT format**: `"signer_groups": ["id1", "id2"]` **WRONG format**: `"signer_groups": [{"id": "id1"}]` (causes "value must be a string" error) --- ## Destination Schemas (Required Fields) ### Crypto Destination ```json POST /recipients/{recipient_id}/destinations { "destination_type": "crypto", "name": "My USDC Wallet", "crypto_address": "0x742d35Cc6634C0532925a3b8D404fA40b5398Ad2", "network_id": "ethereum-mainnet" } ``` ### US Bank Destination (fiat_us) - All Required Fields ```json POST /recipients/{recipient_id}/destinations { "destination_type": "fiat_us", "name": "Business Checking", "aba_routing_number": "021000021", "account_number": "123456789", "account_type": "checking", "account_holder_name": "Acme Corporation", "bank_name": "Chase Bank", "bank_address": { "street1": "383 Madison Avenue", "city": "New York", "country": "US" } } ``` ### International Bank Destination (fiat_iban) - All Required Fields ```json POST /recipients/{recipient_id}/destinations { "destination_type": "fiat_iban", "name": "European Account", "iban": "DE89370400440532013000", "bic": "DEUTDEFFXXX", "account_holder_name": "Acme GmbH", "account_holder_address": { "street1": "Friedrichstraße 123", "city": "Berlin", "country": "DE" }, "bank_name": "Deutsche Bank", "bank_address": { "street1": "Taunusanlage 12", "city": "Frankfurt", "country": "DE" }, "assets": ["EUR"], "capabilities": ["sepa"] } ``` --- ## Supported Assets (Tokens) | Asset | Name | Type | |-------|------|------| | `USD` | US Dollar | Fiat | | `EUR` | Euro | Fiat | | `USDC` | USD Coin | Stablecoin | | `USDT` | Tether | Stablecoin | | `DKUSD` | Dakota USD | Stablecoin | | `ETH` | Ethereum | Native | | `SOL` | Solana | Native | --- ## Payment Rails | Rail | Description | Assets | |------|-------------|--------| | `ach` | US ACH | USD | | `fedwire` | US Fedwire | USD | | `swift` | International SWIFT | USD, EUR | | `sepa` | European SEPA | EUR | --- ## Supported Networks **Mainnet (Production):** `ethereum-mainnet`, `polygon-mainnet`, `arbitrum-mainnet`, `base-mainnet`, `optimism-mainnet`, `solana-mainnet` **Testnet (Sandbox):** `ethereum-sepolia`, `ethereum-holesky`, `base-sepolia`, `arbitrum-sepolia`, `optimism-sepolia`, `polygon-amoy`, `solana-devnet`, `solana-testnet` --- ## Token Availability by Network | Network | USDC | USDT | DKUSD | |---------|------|------|-------| | `ethereum-mainnet` | Yes | Yes | - | | `polygon-mainnet` | Yes | Yes | - | | `arbitrum-mainnet` | Yes | Yes | - | | `base-mainnet` | Yes | Yes | Yes | | `optimism-mainnet` | Yes | Yes | - | | `solana-mainnet` | Yes | Yes | - | --- ## API Specification - [OpenAPI 3.0 Spec (YAML)](https://docs.dakota.io/openapi.yaml): Machine-readable OpenAPI 3.0.3 specification for SDK generation, Postman import, and AI agent integration. ## API Reference - [API Reference](https://docs.dakota.io/api-reference/introduction): Complete API documentation with base URLs, authentication, rate limits (60 req/min for API keys), response formats, data model relationships, filtering/sorting parameters, and bulk operations. - [Error Codes](https://docs.dakota.io/api-reference/errors): HTTP status codes, error response format, and error handling best practices with code examples. Includes anchor links for direct linking to specific error codes. - [State Lifecycles](https://docs.dakota.io/api-reference/state-lifecycles): State transition diagrams for Applications (pending→submitted→completed), Transactions, and Auto Transactions with terminal state identification. ## Authentication & Rate Limits - [API Keys & Headers](https://docs.dakota.io/documentation/authentication/api-keys-headers): Authenticating requests using x-api-key and x-idempotency-key headers. - [Rate Limiting](https://docs.dakota.io/documentation/authentication/rate-limiting): Rate limits by auth type: API Key (60/min), JWT (600/min), Unauthenticated (10/min), Application Token (100/hour). - [Troubleshooting](https://docs.dakota.io/documentation/authentication/troubleshooting): Common authentication issues, error codes, and solutions. ## Docs - [Common Flows](https://docs.dakota.io/documentation/common-flows): Complete code examples for common API integration patterns (wallets, onramp, offramp, transactions). - [Get Started](https://docs.dakota.io/): Welcome to Dakota! Introduction to the platform, core concepts, and getting started with Dakota's financial infrastructure. - [Terminology & Key Concepts](https://docs.dakota.io/documentation/terminology): Key terms and concepts used throughout the Dakota platform and documentation. - [Customer Onboarding](https://docs.dakota.io/documentation/customer-onboarding): Complete guide to onboarding customers to your Dakota-powered application, including KYC/KYB processes and compliance requirements. - [Destinations & Recipients](https://docs.dakota.io/documentation/destinations-recipients): Understanding how to manage payment destinations and recipient configurations for money movement. - [Webhook Integration](https://docs.dakota.io/documentation/webhooks): Event-driven notifications with retry policy (10 attempts over 48 hours), delivery headers, and signature verification. - [Testing Your Integration](https://docs.dakota.io/documentation/testing): Testing strategies, sandbox environments, and best practices for validating your Dakota integration. - [Wallets](https://docs.dakota.io/documentation/wallets): Managing digital wallets, balances, and account structures within the Dakota platform. - [Create Your Flow](https://docs.dakota.io/documentation/create-your-flow): Use the Dakota Funds Flow Builder to visualize and design your payment flows. - [Authentication](https://docs.dakota.io/documentation/authentication): Overview of authentication methods and secure API access. - [Security](https://docs.dakota.io/documentation/authentication/security): Security best practices, encryption, and secure integration patterns. - [Using LLMs](https://docs.dakota.io/documentation/using-llms): Guide on integrating Dakota documentation with AI tools and LLMs. ## Common Errors and Solutions | Error | Cause | Solution | |-------|-------|----------| | `401 Unauthorized` | Missing or invalid API key | Include `X-API-Key: your-api-key` header | | `400 Bad Request` (missing idempotency) | Missing `X-Idempotency-Key` on POST | Add `X-Idempotency-Key: ` header | | `409 Conflict` | Reused idempotency key | Generate new UUID for each unique request | | `customer_not_found` | Customer ID doesn't exist | Verify customer was created | | `customer_not_approved` | Customer KYB not complete | Wait for `kyb_status: "approved"` | | `customer name must be at least 3 characters` | Name too short | Use 3-100 characters | | `a customer with that name already exists` | Duplicate name | Use unique customer name | | `recipient_not_found` | Recipient doesn't exist or wrong client | Verify recipient exists and you own it | | `duplicate_name` | Duplicate recipient name per customer | Use unique recipient name | | `destination_not_found` | Using wallet_id instead of destination_id | Create destination first | | `field 'signer_groups/0': value must be a string` | Objects in signer_groups | Use `["id"]` not `[{"id": "..."}]` | | Invalid public key | Wrong key format | Use ES256 ECDSA P-256, SPKI DER, base64 | | `403 Forbidden` | Accessing another client's resource | You can only access your own resources |