# Integration guide

Two steps: embed the widget, then verify the token on your server. Replace `YOUR_SITE_KEY` / `YOUR_SECRET_KEY` with the keys from your site.

## 1. Add the widget to your page

Drop this into your HTML form. On success the widget injects a hidden `nc-response` field — a plain form submit just works, no custom JavaScript required.

```html
<div data-nordcaptcha data-site-key="YOUR_SITE_KEY"></div>
<script src="https://cdn.nordcaptcha.com/v1/nc.js" async defer></script>
```

## 2. Verify the token on your server

When the form is submitted, exchange the `nc-response` token for a verdict using your secret key. The token is single-use and carries no personal data.

### cURL

```
curl -X POST https://api.nordcaptcha.com/v1/verify \
  -H "content-type: application/json" \
  -d '{"secret": "YOUR_SECRET_KEY", "token": "$NC_TOKEN"}'
```

### Python

```
import requests

r = requests.post("https://api.nordcaptcha.com/v1/verify", json={
    "secret": "YOUR_SECRET_KEY",
    "token": request.POST["nc-response"],
}).json()
if r.get("success"):
    ...  # proceed
```

### Node

```
const res = await fetch("https://api.nordcaptcha.com/v1/verify", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ secret: "YOUR_SECRET_KEY", token: req.body["nc-response"] }),
});
const data = await res.json();
if (data.success) {
  // proceed
}
```

### PHP

```
<?php
$ch = curl_init("https://api.nordcaptcha.com/v1/verify");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ["content-type: application/json"],
  CURLOPT_POSTFIELDS => json_encode(["secret" => "YOUR_SECRET_KEY", "token" => $_POST["nc-response"]]),
]);
$data = json_decode(curl_exec($ch), true);
if (!empty($data["success"])) {
  // proceed
}
```

### Go

```
body, _ := json.Marshal(map[string]string{
    "secret": "YOUR_SECRET_KEY",
    "token":  r.FormValue("nc-response"),
})
resp, _ := http.Post("https://api.nordcaptcha.com/v1/verify",
    "application/json", bytes.NewReader(body))
var data struct{ Success bool `json:"success"` }
json.NewDecoder(resp.Body).Decode(&data)
if data.Success {
    // proceed
}
```

### Ruby

```
require "net/http"
require "json"

res = Net::HTTP.post(URI("https://api.nordcaptcha.com/v1/verify"),
  { secret: "YOUR_SECRET_KEY", token: params["nc-response"] }.to_json,
  "content-type" => "application/json")
if JSON.parse(res.body)["success"]
  # proceed
end
```

## Response & errors

A success returns `{ "success": true, "ts": ..., "hostname": "..." }`. Compare `hostname` against your expected host. On failure you get an HTTP 400 with `{ "detail": { "code": ..., "message": ... } }`:

| Error | Meaning | What to do |
| --- | --- | --- |
| `invalid_site_key` | Secret key wrong, or token not issued for this site. | Check you're sending this site's secret key. |
| `token_expired` | Token is older than its short lifetime. | Reject; have the visitor solve again (`widget.reset()`). |
| `token_already_used` | Token was already verified once (single-use). | Reject; never verify the same token twice. |
