DataParse — это интеллектуальная инфраструктура для сбора и структурирования публичной информации. Наш сайт работает для того, чтобы бизнес мог отказаться от ручного поиска и копирования данных.
Мы собираем информацию с открытых маркетплейсов, кадастровых баз, досок объявлений и реестров, чтобы вы получали готовые к аналитике массивы данных. Это экономит сотни часов ручного труда менеджеров и аналитиков.
Платформа работает как единый цикл: сбор данных по правилам источника, очистка дублей, нормализация полей, контроль качества и выдача в формате, который можно сразу загружать в CRM, BI или внутренние сервисы.
Процесс построен так, чтобы вы быстро получили рабочий результат и могли масштабировать выгрузки без переписывания процессов внутри компании.
Типовой запуск проекта состоит из 6 этапов:
Ниже описана полная схема API по вашей спецификации.
Parsers Servicehttps://your-domain.tld/api/v1
Две модели авторизации:
POST /auth/login с телом
{ username, password } и передается в заголовке
Authorization: Bearer <access_token>.
POST /auth/api-token (с Bearer
JWT), а затем используется в публичном запросе
GET /parse как query-параметр
api_token.
Ключевые эндпоинты:
POST /auth/login — получить JWT access_token.
POST /auth/api-token — получить личный API token.
GET /parse — публичный парс по
api_token, parser,
region.
GET /parsers/my — список доступных активных
парсеров пользователя (через JWT).
PATCH /admin/users/:userId/parser-access-ids —
назначить доступы к парсерам (admin).
PATCH /admin/parser/:parserId/active — глобально
включить/выключить парсер (admin).
/parse не требует
JWT, но валидирует api_token, блокировку
пользователя, доступ к парсеру и лимиты.
Поток использования выглядит так: логин по JWT, получение
личного API token, запрос списка доступных парсеров, затем
публичный вызов /parse с параметром
api_token.
POST /auth/login с
{ "username": "...", "password": "..." }.
POST /auth/api-token с заголовком
Authorization: Bearer <access_token>.
GET /parsers/my (JWT) вернет только активные
парсеры, к которым у пользователя есть доступ.
GET
/parse?api_token=...&parser=...®ion=....
Контракт публичного parse-запроса:
GET /parse
Query:
api_token: string (required)
parser: integer (required)
region: string (required)
Коды ответов для /parse:
parserPrefix).
isActive=false).
Админ-ручки:
PATCH /admin/users/:userId/parser-access-ids —
выдать пользователю доступы к парсерам.
PATCH /admin/parser/:parserId/active — глобально
включить/выключить парсер.
Подробные ответы по эндпоинтам:
POST /auth/api-token: 200
{ token }, 401/403 — JWT
истек/нет доступа.
GET /parsers/my: 200 список
активных доступных парсеров, 401/403 —
пользователь заблокирован или нет JWT.
PATCH /admin/users/:userId/parser-access-ids:
200 { success, user, parsers },
400 невалидное тело, 403 нет
admin-прав или попытка менять admin-пользователя,
404 user/parserId не найден.
PATCH /admin/parser/:parserId/active:
200 { success, parser },
400 isActive не boolean,
401/403 нет admin-доступа,
404 parser не найден.
JwtAuthGuard + RolesGuard) и требуют
admin права.
Ниже полный PHP-flow по вашему API: логин, получение personal
API token, чтение доступных парсеров и публичный parse-запрос с
api_token.
<?php
$baseUrl = 'https://your-domain.tld/api/v1';
$username = 'demo_user';
$password = 'demo_password';
function postJson($url, $body, $headers = []) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => array_merge(['Content-Type: application/json'], $headers),
CURLOPT_POSTFIELDS => json_encode($body, JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return [$status, json_decode($response, true)];
}
function getJson($url, $headers = []) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return [$status, json_decode($response, true)];
}
// 1) login -> JWT access_token
[$loginStatus, $loginBody] = postJson(
"$baseUrl/auth/login",
['username' => $username, 'password' => $password]
);
$accessToken = $loginBody['accessToken'] ?? null;
// 2) get personal API token
[$tokenStatus, $tokenBody] = postJson(
"$baseUrl/auth/api-token",
[],
["Authorization: Bearer {$accessToken}"]
);
$apiToken = $tokenBody['token'] ?? null;
// 3) list my parsers
[$parsersStatus, $parsers] = getJson(
"$baseUrl/parsers/my",
["Authorization: Bearer {$accessToken}"]
);
// 4) parse by api_token (public)
$parserId = 1;
$region = 'moscow';
[$parseStatus, $parseData] = getJson(
"$baseUrl/parse?api_token={$apiToken}&parser={$parserId}®ion={$region}"
);
print_r(compact(
'loginStatus',
'tokenStatus',
'parsersStatus',
'parseStatus',
'parseData'
));
/auth/api-token работает только с валидным Bearer
access_token.
401/403 — токен/доступ/лимит, 404 —
parser not found, 410 — parser выключен.
Admin пример (PHP):
// PATCH /admin/users/:userId/parser-access-ids
// PATCH /admin/parser/:parserId/active
// Требуется Bearer <admin_access_token>
Node.js сценарий повторяет контракт 1:1. Сначала JWT, затем
личный API token, потом публичный /parse.
const BASE_URL = 'https://your-domain.tld/api/v1';
async function login(username, password) {
const response = await fetch(`${BASE_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
if (!response.ok) throw new Error('Login failed');
return response.json(); // { accessToken, ... }
}
async function getApiToken(accessToken) {
const response = await fetch(`${BASE_URL}/auth/api-token`, {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}` },
});
if (!response.ok) throw new Error('Get API token failed');
return response.json(); // { token }
}
async function getMyParsers(accessToken) {
const response = await fetch(`${BASE_URL}/parsers/my`, {
headers: { Authorization: `Bearer ${accessToken}` },
});
if (!response.ok) throw new Error('Get parsers failed');
return response.json();
}
async function parsePublic(apiToken, parserId, region) {
const query = new URLSearchParams({
api_token: apiToken,
parser: String(parserId),
region,
});
const response = await fetch(`${BASE_URL}/parse?${query.toString()}`);
return { status: response.status, body: await response.json() };
}
const { accessToken } = await login('demo_user', 'demo_password');
const { token: apiToken } = await getApiToken(accessToken);
const parsers = await getMyParsers(accessToken);
const parserId = parsers[0]?.id ?? 1;
const parseResult = await parsePublic(apiToken, parserId, 'moscow');
console.log(parseResult);
/auth/api-token,
/parsers/my), а api_token — для
публичного /parse.
401/403/404/410 отдельными ветками
с разной логикой retry.
parserId, region,
userId, чтобы быстрее разбирать инциденты доступа
и лимитов.
Admin вызовы в Node.js:
// PATCH /admin/users/:userId/parser-access-ids
await fetch(`${BASE_URL}/admin/users/12/parser-access-ids`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${adminAccessToken}`,
},
body: JSON.stringify({ parserAccessIds: [1, 2, 3] }),
});
// PATCH /admin/parser/:parserId/active
await fetch(`${BASE_URL}/admin/parser/7/active`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${adminAccessToken}`,
},
body: JSON.stringify({ isActive: false }),
});
TypeScript-слой помогает зафиксировать контракт ответов и исключить ошибки интеграции еще на этапе компиляции.
const BASE_URL = 'https://your-domain.tld/api/v1';
type LoginResponse = { accessToken: string };
type ApiTokenResponse = { token: string };
type ParseErrorCode = 401 | 403 | 404 | 410;
type ParseSuccess = Record<string, unknown>;
interface ParseResult {
status: number;
body: ParseSuccess | { message?: string };
}
async function login(username: string, password: string): Promise<LoginResponse> {
const response = await fetch(`${BASE_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
if (!response.ok) throw new Error('Login failed');
return response.json() as Promise<LoginResponse>;
}
async function getApiToken(accessToken: string): Promise<ApiTokenResponse> {
const response = await fetch(`${BASE_URL}/auth/api-token`, {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}` },
});
if (!response.ok) throw new Error('API token issue failed');
return response.json() as Promise<ApiTokenResponse>;
}
async function parseByApiToken(
apiToken: string,
parser: number,
region: string,
): Promise<ParseResult> {
const query = new URLSearchParams({
api_token: apiToken,
parser: String(parser),
region,
});
const response = await fetch(`${BASE_URL}/parse?${query.toString()}`);
return { status: response.status, body: await response.json() };
}
/auth/* и /parse разные,
лучше разделять интерфейсы.
Для NestJS оптимально вынести внешние вызовы в сервис и использовать его в use-case слое: логин, выдача API token, список парсеров, публичный parse и admin-операции.
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
@Injectable()
export class ParsersServiceClient {
private readonly baseUrl = 'https://your-domain.tld/api/v1';
constructor(private readonly http: HttpService) {}
async login(username: string, password: string) {
const { data } = await firstValueFrom(
this.http.post(`${this.baseUrl}/auth/login`, { username, password }),
);
return data; // { accessToken }
}
async getApiToken(accessToken: string) {
const { data } = await firstValueFrom(
this.http.post(
`${this.baseUrl}/auth/api-token`,
{},
{ headers: { Authorization: `Bearer ${accessToken}` } },
),
);
return data; // { token }
}
async getMyParsers(accessToken: string) {
const { data } = await firstValueFrom(
this.http.get(`${this.baseUrl}/parsers/my`, {
headers: { Authorization: `Bearer ${accessToken}` },
}),
);
return data;
}
async parseByApiToken(apiToken: string, parser: number, region: string) {
const { data } = await firstValueFrom(
this.http.get(`${this.baseUrl}/parse`, {
params: { api_token: apiToken, parser, region },
}),
);
return data;
}
async setUserParserAccess(
adminAccessToken: string,
userId: number,
parserAccessIds: number[],
) {
const { data } = await firstValueFrom(
this.http.patch(
`${this.baseUrl}/admin/users/${userId}/parser-access-ids`,
{ parserAccessIds },
{ headers: { Authorization: `Bearer ${adminAccessToken}` } },
),
);
return data;
}
async setParserActive(
adminAccessToken: string,
parserId: number,
isActive: boolean,
) {
const { data } = await firstValueFrom(
this.http.patch(
`${this.baseUrl}/admin/parser/${parserId}/active`,
{ isActive },
{ headers: { Authorization: `Bearer ${adminAccessToken}` } },
),
);
return data;
}
}
admin.
401/403/404/410 в понятные
domain exceptions внутри Nest-приложения.
timeout, retry и structured logging c
requestId/userId.
React-сценарий лучше строить через custom hook: логин, выдача API token, загрузка списка парсеров, запуск parse и отображение результата/ошибок в UI.
import { useCallback, useState } from 'react';
const BASE_URL = 'https://your-domain.tld/api/v1';
async function login(username, password) {
const response = await fetch(`${BASE_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
if (!response.ok) throw new Error('Login failed');
return response.json();
}
export function useParsersApi() {
const [accessToken, setAccessToken] = useState(null);
const [apiToken, setApiToken] = useState(null);
const [parsers, setParsers] = useState([]);
const [state, setState] = useState('idle');
const [result, setResult] = useState(null);
const authorize = useCallback(async (username, password) => {
const auth = await login(username, password);
setAccessToken(auth.accessToken);
const tokenResp = await fetch(`${BASE_URL}/auth/api-token`, {
method: 'POST',
headers: { Authorization: `Bearer ${auth.accessToken}` },
});
const tokenData = await tokenResp.json();
setApiToken(tokenData.token);
const parsersResp = await fetch(`${BASE_URL}/parsers/my`, {
headers: { Authorization: `Bearer ${auth.accessToken}` },
});
setParsers(await parsersResp.json());
setState('authorized');
}, []);
const parse = useCallback(async (parserId, region) => {
setState('loading');
const query = new URLSearchParams({
api_token: apiToken,
parser: String(parserId),
region,
});
const response = await fetch(`${BASE_URL}/parse?${query.toString()}`);
const body = await response.json();
setResult({ status: response.status, body });
setState(response.ok ? 'done' : 'error');
}, [apiToken]);
return { accessToken, apiToken, parsers, state, result, authorize, parse };
}
401/403/404/410 с
понятным текстом.
Для Vue 3 используйте composable с двумя этапами: авторизация (JWT + api_token) и публичный parse по выбранному парсеру и региону.
import { ref } from 'vue';
const BASE_URL = 'https://your-domain.tld/api/v1';
export function useParsersApi() {
const accessToken = ref(null);
const apiToken = ref(null);
const parsers = ref([]);
const state = ref('idle');
const result = ref(null);
const authorize = async (username, password) => {
const loginResp = await fetch(`${BASE_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
const loginData = await loginResp.json();
accessToken.value = loginData.accessToken;
const tokenResp = await fetch(`${BASE_URL}/auth/api-token`, {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken.value}` },
});
const tokenData = await tokenResp.json();
apiToken.value = tokenData.token;
const parsersResp = await fetch(`${BASE_URL}/parsers/my`, {
headers: { Authorization: `Bearer ${accessToken.value}` },
});
parsers.value = await parsersResp.json();
state.value = 'authorized';
};
const parse = async (parserId, region) => {
const query = new URLSearchParams({
api_token: apiToken.value,
parser: String(parserId),
region,
});
const response = await fetch(`${BASE_URL}/parse?${query.toString()}`);
const body = await response.json();
result.value = { status: response.status, body };
state.value = response.ok ? 'done' : 'error';
};
return { accessToken, apiToken, parsers, state, result, authorize, parse };
}
401/403/404/410 выводите разные сообщения и
действия для пользователя.
parsers и отдельный селект региона перед
вызовом parse.
В вашей архитектуре публичный parse возвращает данные в формате
конкретного парсера. Поэтому интеграция должна опираться на
parserPrefix, который связан с выбранным
parserId.
Что именно означает "форматы" в этом API:
format=csv/xlsx в API
нет:
базовый ответ приходит в JSON, при необходимости конвертируйте
у себя в CSV/XLSX.
1) Формат запроса (public parse):
Базовый публичный запрос:
GET /api/v1/parse?api_token=...&parser=1®ion=moscow
Обязательные параметры:
api_token — personal API token пользователя.
parser — ID парсера (integer).region — регион в формате, который поддерживает
выбранный parser.
2) Формат служебных auth-запросов:
POST /api/v1/auth/login
Content-Type: application/json
{
"username": "string",
"password": "string"
}
POST /api/v1/auth/api-token
Authorization: Bearer <access_token>
Content-Type: application/json
{}
3) Формат admin-запросов (JSON body):
PATCH /api/v1/admin/users/:userId/parser-access-ids
Authorization: Bearer <admin_access_token>
Content-Type: application/json
{
"parserAccessIds": [1, 2, 3]
}
PATCH /api/v1/admin/parser/:parserId/active
Authorization: Bearer <admin_access_token>
Content-Type: application/json
{
"isActive": true
}
Служебные ручки, которые обеспечивают стабильный flow:
POST /auth/login — получить JWT access_token.
POST /auth/api-token — получить personal API
token по JWT.
GET /parsers/my — получить список активных
парсеров, доступных пользователю.
Admin ручки для управления доступами:
PATCH /admin/users/:userId/parser-access-ids
PATCH /admin/parser/:parserId/activeКоды ответов и конкретные действия:
/parsers/my и
заново выбрать parser.
4) Формат успешного ответа (пример структуры):
{
"status": 200,
"data": {
"parserId": 1,
"region": "moscow",
"items": [
{ "title": "Example item", "url": "https://example.com/item/1" }
]
}
}
5) Формат ошибок (пример):
{
"status": 403,
"message": "Нет доступа к выбранному парсеру"
}
userId, parser, region,
HTTP-код, время и requestId для быстрой
диагностики.
Деятельность сервиса строго регламентирована законодательством РФ в сфере открытой информации.
Мы никогда не занимаемся сбором:
• Закрытой персональной информации
• Коммерческой тайны
• Данных за авторизацией (взлом аккаунтов)
Вся работа идет исключительно с публично представленной информацией (OSINT подход), что делает покупку и хранение таких баз абсолютно законным для вашего бизнеса.
Для технической безопасности мы применяем разграничение доступов, журналирование действий в API и контроль ролей пользователей. Ключи и токены доступа должны храниться в защищенных переменных окружения, а не в открытом клиентском коде.
Настоящая политика описывает, какие данные мы получаем, как обрабатываем и как защищаем информацию пользователей сервиса DataParse.
Используя сайт и API, вы соглашаетесь с обработкой данных в рамках этой политики и действующего законодательства.
По вопросам конфиденциальности и удалению данных вы можете обратиться через форму обратной связи на сайте или по контактам, указанным в вашем договоре обслуживания.