Быстрый старт
Создайте OAuth-приложение, получите DPoP-токен и сделайте первый запрос.
Регистрация
Зайдите на app.legalstack.ru/register и создайте команду. Вы станете её владельцем: OAuth-приложения создают только владелец и администраторы команды.
OAuth-приложение
В разделе «Настройки → API» откройте вкладку «OAuth-приложения», нажмите «Новое OAuth-приложение», отметьте grant-тип client_credentials и сохраните client_id и client_secret.
Секрет показывается один раз
Сохраните client_secret сразу: после закрытия окна его можно только перевыпустить.
Ключ DPoP
Каждый токен платформы привязан к ключу клиента: вместе с токеном в каждом запросе передаётся подписанное этим ключом доказательство, см. гайд Аутентификация. Поэтому первым делом создайте пару ключей и функцию, которая подписывает доказательство для конкретного запроса.
import { createHash, randomUUID } from 'node:crypto';
import { exportJWK, generateKeyPair, SignJWT } from 'jose';
const { privateKey, publicKey } = await generateKeyPair('ES256');
const jwk = await exportJWK(publicKey);
const hash = (value) => createHash('sha256').update(value).digest('base64url');
export const proof = (method, url, { nonce, accessToken } = {}) =>
new SignJWT({
htm: method,
htu: url,
jti: randomUUID(),
...(nonce ? { nonce } : {}),
...(accessToken ? { ath: hash(accessToken) } : {}),
})
.setProtectedHeader({ typ: 'dpop+jwt', alg: 'ES256', jwk })
.setIssuedAt()
.sign(privateKey);Получение токена
Первый запрос к точке выдачи токенов получает 400 с error: use_dpop_nonce и заголовком DPoP-Nonce. Повторите запрос, включив это значение в доказательство, и сохраняйте nonce из каждого следующего ответа.
const TOKEN_URL = 'https://api.legalstack.ru/oauth/token';
let nonce;
async function requestToken() {
const body = new URLSearchParams({
grant_type: 'client_credentials',
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
scope: 'registry:read tasks:read',
resource: 'https://api.legalstack.ru',
});
const response = await fetch(TOKEN_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded', DPoP: await proof('POST', TOKEN_URL, { nonce }) },
body,
});
nonce = response.headers.get('DPoP-Nonce') ?? nonce;
const json = await response.json();
if (response.status === 400 && json.error === 'use_dpop_nonce') return requestToken();
return json.access_token;
}
const accessToken = await requestToken();{
"access_token": "eyJhbGciOiJFZERTQSIsImtpZCI6...",
"token_type": "DPoP",
"expires_in": 900,
"scope": "registry:read tasks:read"
}expires_in — время жизни в секундах. Запрашивайте только те scope, которые нужны интеграции: полный список — в каталоге scope, правила выдачи и обновления — в гайде Аутентификация.
Первый запрос
Токен передаётся со схемой DPoP, а доказательство для запроса включает ath — хеш токена — и nonce из последнего ответа. На 401 с кодом USE_DPOP_NONCE повторите запрос с новым nonce из заголовка.
async function api(method, path) {
const url = `https://api.legalstack.ru${path}`;
const response = await fetch(url, {
method,
headers: { Authorization: `DPoP ${accessToken}`, DPoP: await proof(method, url, { nonce, accessToken }) },
});
nonce = response.headers.get('DPoP-Nonce') ?? nonce;
if (response.status === 401 && (await response.clone().json()).code === 'USE_DPOP_NONCE') return api(method, path);
return response.json();
}
const tasks = await api('GET', '/api/v1/tasks');Ответ — JSON-массив задач вашей команды. Ошибки приходят в формате Problem Details, см. гайд Ошибки.
Требования к клиенту
Только TLS 1.3
api.legalstack.ru и остальные домены платформы принимают только TLS 1.3. Штатные curl и PowerShell в Windows 10 не подключаются: используйте curl с OpenSSL, Windows 11, любой современный HTTP-клиент или язык с поддержкой TLS 1.3.
Одного curl для работы с API недостаточно: каждому запросу нужно подписанное доказательство DPoP, поэтому используйте язык с библиотекой JOSE, как в примерах выше.
Дальше: Аутентификация, справочник API и обработка ошибок.