> Toden documentation. For the full index fetch /llms.txt. Every page is available as Markdown by appending .md to its URL. Identity verification uses /api/kyc, Risk Intelligence uses /api/v1; they are separate contracts with different error shapes. Never invent an endpoint, field or enum value: read the API reference page for the operation first.

# Server SDKs: Node, Go, Python and more

> Status of Toden server SDKs for Node.js, Python, Go and other backend languages, with working REST examples you can use now.

Your backend talks to Toden with a **secret key**: to create sessions, read verification results, and make every Risk Intelligence call. This page says honestly what exists for each language today.

## What is available

| Language             | Status                                                           | What to use now                                              |
| -------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------ |
| Node.js / TypeScript | Generated from the API contracts. **Not yet published to npm.**  | The REST API, or generate the client yourself (below)        |
| Python               | Generated from the API contracts. **Not yet published to PyPI.** | The REST API, or generate the client yourself (below)        |
| Go                   | Not available as a packaged SDK                                  | The REST API, or generate a client from the OpenAPI contract |
| Java, C#, PHP, Ruby  | Not available as a packaged SDK                                  | The REST API, or generate a client from the OpenAPI contract |

> **Warning**
>
> Do not add `@myazahq/trust-sdk` or any Toden server package as a dependency until this page lists it as published. An unpublished package name can be claimed by someone else on a public registry.

Client SDKs for capturing a verification (React, React Native, Flutter) **are** published. See [Choose an SDK](/integrate/sdks/overview).

## Call the API directly

The API is plain JSON over HTTPS, so every language works today. The examples below make the same Sandbox request: a transaction decision.

Set your key in the environment first. Never write it into source.

```bash
export TODEN_SECRET_KEY="sk_test_..."
```

**`Node.js`**

```typescript title="Node.js"
// Node.js 20 or later. No dependencies.
const response = await fetch("https://sandbox-api.toden.co/api/v1/transactions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TODEN_SECRET_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "order-1001-payment",
  },
  body: JSON.stringify({
    externalActivityId: "order-1001-payment",
    subject: { type: "individual", externalUserId: "user_42" },
    occurredAt: new Date().toISOString(),
    transaction: {
      externalTransactionId: "transfer-1001",
      assetClass: "fiat",
      direction: "outbound",
      amount: "12500.00",
      currency: "NGN",
      transactionType: "bank_transfer",
      parties: [
        { role: "sender", externalUserId: "user_42" },
        { role: "recipient", externalPartyId: "supplier-7", type: "business", displayName: "Sample Supplier" },
      ],
    },
  }),
});

const body = await response.json();
if (!response.ok) {
  // /api/v1 errors: { error: { type, code, message, request_id } }
  throw new Error(`${body.error.type} ${body.error.code} (${body.error.request_id})`);
}
console.log(body.assessment.summary.outcome);
```

**`Python`**

```python title="Python"
# Python 3.9 or later, with the requests package.
import os
from datetime import datetime, timezone

import requests

response = requests.post(
    "https://sandbox-api.toden.co/api/v1/transactions",
    headers={
        "Authorization": f"Bearer {os.environ['TODEN_SECRET_KEY']}",
        "Idempotency-Key": "order-1001-payment",
    },
    json={
        "externalActivityId": "order-1001-payment",
        "subject": {"type": "individual", "externalUserId": "user_42"},
        "occurredAt": datetime.now(timezone.utc).isoformat(),
        "transaction": {
            "externalTransactionId": "transfer-1001",
            "assetClass": "fiat",
            "direction": "outbound",
            "amount": "12500.00",
            "currency": "NGN",
            "transactionType": "bank_transfer",
            "parties": [
                {"role": "sender", "externalUserId": "user_42"},
                {"role": "recipient", "externalPartyId": "supplier-7",
                 "type": "business", "displayName": "Sample Supplier"},
            ],
        },
    },
    timeout=30,
)
body = response.json()
if not response.ok:
    error = body["error"]
    raise RuntimeError(f"{error['type']} {error['code']} ({error['request_id']})")
print(body["assessment"]["summary"]["outcome"])
```

**`Go`**

```go title="Go"
// Go 1.21 or later. Standard library only.
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
)

func main() {
	payload, _ := json.Marshal(map[string]any{
		"externalActivityId": "order-1001-payment",
		"subject":            map[string]any{"type": "individual", "externalUserId": "user_42"},
		"occurredAt":         time.Now().UTC().Format(time.RFC3339),
		"transaction": map[string]any{
			"externalTransactionId": "transfer-1001",
			"assetClass":            "fiat",
			"direction":             "outbound",
			"amount":                "12500.00",
			"currency":              "NGN",
			"transactionType":       "bank_transfer",
			"parties": []map[string]any{
				{"role": "sender", "externalUserId": "user_42"},
				{"role": "recipient", "externalPartyId": "supplier-7", "type": "business", "displayName": "Sample Supplier"},
			},
		},
	})

	request, _ := http.NewRequest(http.MethodPost, "https://sandbox-api.toden.co/api/v1/transactions", bytes.NewReader(payload))
	request.Header.Set("Authorization", "Bearer "+os.Getenv("TODEN_SECRET_KEY"))
	request.Header.Set("Content-Type", "application/json")
	request.Header.Set("Idempotency-Key", "order-1001-payment")

	client := &http.Client{Timeout: 30 * time.Second}
	response, err := client.Do(request)
	if err != nil {
		panic(err) // A failed call is never an approval. Hold the payment.
	}
	defer response.Body.Close()

	var body map[string]any
	json.NewDecoder(response.Body).Decode(&body)
	if response.StatusCode >= 300 {
		panic(fmt.Sprintf("toden: %v", body["error"]))
	}
	summary := body["assessment"].(map[string]any)["summary"].(map[string]any)
	fmt.Println(summary["outcome"])
}
```

**What you should see:** a `2xx` response whose `assessment.summary.outcome` is `allow`, `review` or `block`. Sending the same request again with the same `Idempotency-Key` returns the original decision. The full walkthrough is the [Risk Intelligence quickstart](/risk-intelligence/quickstart).

## Rules every server integration must follow

* The secret key comes from the environment or a secrets manager. It never reaches a browser, a mobile app, a log line or a repository.
* `/api/kyc` and `/api/v1` return different error bodies. Parse each one separately. See [Errors](/get-started/errors).
* Make writes safe to retry. See [Requests, retries and idempotency](/api-reference/conventions).
* A failed or timed-out risk decision is not an approval.
* Verify every webhook signature on the raw request bytes. See [Verify signatures](/integrate/webhooks/signatures).

## Generate a client from the contracts

Both API contracts are OpenAPI 3.1 documents, so you can generate a typed client in your own language today.

| Contract              | Covers                      | URL                                                  |
| --------------------- | --------------------------- | ---------------------------------------------------- |
| Risk Intelligence     | `/api/v1`                   | `https://api.toden.co/api/openapi.json`              |
| Identity verification | `/api/kyc`, `/api/identity` | `https://api.toden.co/api/openapi/verification.json` |

#### Go

```bash
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
curl -sS https://api.toden.co/api/openapi.json -o toden-risk.json
oapi-codegen -generate types,client -package toden toden-risk.json > toden/client.gen.go
```

#### Any language

```bash
# OpenAPI Generator supports Java, C#, PHP, Ruby, Kotlin and more.
npx @openapitools/openapi-generator-cli generate \
  -i https://api.toden.co/api/openapi.json \
  -g java -o ./toden-java
```

> **Note**
>
> These are third-party generators and the output is yours to maintain. They are labelled here as a working route, not as supported Toden SDKs. A client you generate is only as current as the contract you generated it from, so regenerate when the [changelog](/changelog) announces a change.

## Next steps

#### [API reference](/api-reference/overview)

#### [First risk decision](/risk-intelligence/quickstart)

#### [Create a session](/user-verification/server-api/create-session)