Готовые примеры интеграции

Node.js

Сайту на Node.js код писать не нужно — клиент на TypeScript.

const API = 'https://api.opotopo.com';

async function sync(items) {
  const response = await fetch(`${API}/rest/v1/advertisement/seller/ads/sync`, {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.OPOTOPO_API_KEY,
      'Idempotency-Key': crypto.randomUUID(),
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ publish: true, items }),
  });
  if (response.status === 429) {
    const retryAfter = Number(response.headers.get('Retry-After') ?? 60);
    await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
    return sync(items);
  }
  if (!response.ok) throw new Error(await response.text());
  const result = await response.json();
  return result.results.filter((row) => row.error);
}

PHP

Сайту на PHP код писать не нужно — клиент на PHP, на Laravel — клиент для Laravel, магазину на WooCommerce — клиент для WooCommerce, на 1С-Битрикс — клиент для 1С-Битрикс.

function opotopoSync(array $items): array
{
    $retryAfter = 60;
    $curl = curl_init('https://api.opotopo.com/rest/v1/advertisement/seller/ads/sync');
    curl_setopt_array($curl, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'X-API-Key: ' . getenv('OPOTOPO_API_KEY'),
            'Idempotency-Key: ' . bin2hex(random_bytes(16)),
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode(['publish' => true, 'items' => $items]),
        CURLOPT_HEADERFUNCTION => function ($curl, string $header) use (&$retryAfter): int {
            if (stripos($header, 'Retry-After:') === 0) {
                $retryAfter = (int) trim(substr($header, strlen('Retry-After:')));
            }
            return strlen($header);
        },
    ]);
    $body = curl_exec($curl);
    $status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);

    if ($status === 429) {
        sleep($retryAfter);
        return opotopoSync($items);
    }
    if ($status < 200 || $status >= 300) {
        throw new RuntimeException((string) $body);
    }

    return array_values(array_filter(
        json_decode($body, true)['results'],
        fn (array $row) => $row['error'] ?? null,
    ));
}

Порядок работы

  1. Один раз сопоставьте свои категории с категориями площадки и сохраните соответствие.
  2. Передавайте позиции пачками в пределах потолка пакета из справочника операций, не весь каталог одним запросом.
  3. Разбирайте построчный ответ: успешные запоминайте по идентификатору объявления, отклонённые чините и повторяйте.
  4. Передавайте повторно только изменившиеся позиции — так вы не упрётесь в ограничение частоты.
  5. Ставьте прогон на расписание своей системы — планировщик приложения либо задание cron у хостера; каталогу, который меняется редко, хватает суточного прогона.
Статья была полезна?

Не нашли ответ на свой вопрос?

Создать обращение