Skip to content

Submit a URL through the API

Use POST /api/update to queue a public page for indexing or re-indexing in your Dzen Chat project. The examples below use the hosted service at https://chat.dzen.dev. For a local installation, change api_url or $apiUrl to https://local.dzenchat.com/api/update and configure trust for its TLS certificate.

Create an API client

  1. Open your project in Dzen Chat and choose Settings → API clients.
  2. Choose Add, enter a name, and select the website sources this client may update.
  3. Copy CHAT_CLIENT_ID and CHAT_CLIENT_SECRET. The secret is displayed only once; store it in your server's secret manager or environment.
  4. Set those environment variables in the process that runs your integration. Replace https://example.com/docs/page in the example with a public URL belonging to an assigned source.

Keep the secret on your server. Browser JavaScript must never contain it. For a manually created client, New secret invalidates the old secret immediately; update the calling application's environment before its next request. Integration-managed clients are changed through the integration's reconnection flow.

Sign the request

Send an application/x-www-form-urlencoded POST with these fields:

Field Value
client_id Your API client ID.
url The full public page URL to process.
timestamp Current Unix time in seconds. The default allowed clock difference is 60 seconds.
nonce A fresh random value for each request. Reused nonces are rejected.
signature Lowercase hexadecimal HMAC-SHA256 calculated with the client secret.

To calculate the signature, sort the four fields excluding signature by key and join the raw key=value strings with a newline, with no final newline:

client_id=...
nonce=...
timestamp=...
url=...

Sign the UTF-8 bytes before form encoding. Add the signature to the form and then encode the body. The examples generate the timestamp, nonce and signature for every call.

Python

Install requests in your application's virtual environment:

venv/bin/python -m pip install requests

Save the following as submit_url.py and run it with venv/bin/python submit_url.py after setting the two environment variables.

import hashlib
import hmac
import os
import secrets
import time

import requests

api_url = "https://chat.dzen.dev/api/update"
client_id = os.environ["CHAT_CLIENT_ID"]
client_secret = os.environ["CHAT_CLIENT_SECRET"]
url = "https://example.com/docs/page"

timestamp = str(int(time.time()))
nonce = secrets.token_hex(16)
form = {
    "url": url,
    "client_id": client_id,
    "timestamp": timestamp,
    "nonce": nonce,
}
payload = "\n".join(f"{key}={value}" for key, value in sorted(form.items()))
signature = hmac.new(
    client_secret.encode("utf-8"),
    payload.encode("utf-8"),
    hashlib.sha256,
).hexdigest()
form["signature"] = signature

response = requests.post(
    api_url,
    data=form,
    timeout=30,
)
response.raise_for_status()
print(response.json())

PHP

Use PHP with the cURL extension. Save this example as submit_url.php and run php submit_url.php with the same environment variables.

<?php
$apiUrl = 'https://chat.dzen.dev/api/update';
$clientId = getenv('CHAT_CLIENT_ID');
$clientSecret = getenv('CHAT_CLIENT_SECRET');
$url = 'https://example.com/docs/page';

if (!$clientId || !$clientSecret) {
    throw new RuntimeException('Set CHAT_CLIENT_ID and CHAT_CLIENT_SECRET');
}

$timestamp = (string) time();
$nonce = bin2hex(random_bytes(16));
$form = [
    'url' => $url,
    'client_id' => $clientId,
    'timestamp' => $timestamp,
    'nonce' => $nonce,
];
ksort($form);
$payload = implode("\n", array_map(
    static fn ($key, $value) => "{$key}={$value}",
    array_keys($form),
    $form
));
$signature = hash_hmac('sha256', $payload, $clientSecret);
$form['signature'] = $signature;

$body = http_build_query($form, '', '&');

$ch = curl_init($apiUrl);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $body,
    CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);

$response = curl_exec($ch);
if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException($response);
}

echo $response;

Response and troubleshooting

A successful request returns HTTP 202:

{
  "status": "ok",
  "action": "queued",
  "url": "https://example.com/docs/page",
  "final_url": null,
  "message": "Document update queued"
}

This confirms that processing was queued. Check the page's status in Dzen Chat to confirm indexing completed.

Status What to check
400 Required fields, URL syntax, and timestamp freshness.
401 Active client, secret, exact signature payload, and a fresh nonce.
403 Source assignment and allowed URL. Integration clients are restricted to their site's origin and path prefix.
415 Send a form body, not JSON.
429 Reduce request frequency; any later attempt needs a fresh timestamp, nonce and signature.

Manual clients can submit URLs on assigned source domains and their subdomains. Integration clients additionally enforce the authorized site's scheme, host, port and path prefix, and cannot modify a page belonging to another source.

For a local TLS certificate, provide its issuing CA through REQUESTS_CA_BUNDLE for Python or configure PHP/cURL's CA trust. Keep certificate verification enabled.

The instance's OpenAPI reference describes the request schema. This form-based endpoint is separate from the Integration API required by the WordPress plugin.