diff --git a/src/App.tsx b/src/App.tsx
index 33f220f..fce6599 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -32,6 +32,7 @@ import { ErrorBoundary } from './components/ErrorBoundary';
import { PermissionRoute } from '@/components/auth/PermissionRoute';
import { saveReturnUrl } from './utils/token';
import { useAnalyticsCounters } from './hooks/useAnalyticsCounters';
+import { useSiteVerification } from './hooks/useSiteVerification';
// Auth pages - load immediately (small)
import Login from './pages/Login';
import TelegramCallback from './pages/TelegramCallback';
@@ -229,6 +230,9 @@ function LegacySubscriptionRedirect() {
function App() {
useAnalyticsCounters();
+ // Pulls site-verification tokens (Antilopay apay-tag etc.) from the bot
+ // backend and injects matching tags into document.head.
+ useSiteVerification();
return (
<>
diff --git a/src/api/siteVerification.ts b/src/api/siteVerification.ts
new file mode 100644
index 0000000..c11686b
--- /dev/null
+++ b/src/api/siteVerification.ts
@@ -0,0 +1,16 @@
+import { apiClient } from './client';
+
+export interface SiteVerification {
+ apay_tag: string | null;
+}
+
+/**
+ * Public, unauthenticated endpoint — payment-provider crawlers (Antilopay)
+ * need to be able to read these values to validate site ownership.
+ */
+export const siteVerificationApi = {
+ async get(): Promise {
+ const { data } = await apiClient.get('/cabinet/public/site-verification');
+ return data;
+ },
+};
diff --git a/src/hooks/useSiteVerification.ts b/src/hooks/useSiteVerification.ts
new file mode 100644
index 0000000..b7b68db
--- /dev/null
+++ b/src/hooks/useSiteVerification.ts
@@ -0,0 +1,56 @@
+import { useEffect } from 'react';
+import { siteVerificationApi } from '../api/siteVerification';
+
+/**
+ * Fetches the configured site-verification tokens from the bot backend
+ * and injects the matching `` tags into `document.head`.
+ *
+ * Used by Antilopay's verification flow (lk.antilopay.com → Проект →
+ * Верификация → Способ 1: мета-тег). Once the merchant copies the
+ * Antilopay-provided value into `ANTILOPAY_APAY_VERIFICATION_TAG`,
+ * the cabinet will start rendering ``
+ * automatically — no rebuild required.
+ *
+ * The hook is no-op on backend errors (verification is a best-effort
+ * concern and must never block the cabinet from rendering).
+ */
+export function useSiteVerification(): void {
+ useEffect(() => {
+ let cancelled = false;
+
+ siteVerificationApi
+ .get()
+ .then((data) => {
+ if (cancelled) return;
+ if (data.apay_tag) {
+ upsertMetaTag('apay-tag', data.apay_tag);
+ } else {
+ removeMetaTag('apay-tag');
+ }
+ })
+ .catch(() => {
+ // Silent fail — verification meta is best-effort, doesn't block UI.
+ });
+
+ return () => {
+ cancelled = true;
+ };
+ }, []);
+}
+
+function upsertMetaTag(name: string, content: string): void {
+ let tag = document.head.querySelector(`meta[name="${name}"]`);
+ if (!tag) {
+ tag = document.createElement('meta');
+ tag.setAttribute('name', name);
+ document.head.appendChild(tag);
+ }
+ tag.setAttribute('content', content);
+}
+
+function removeMetaTag(name: string): void {
+ const tag = document.head.querySelector(`meta[name="${name}"]`);
+ if (tag) {
+ tag.remove();
+ }
+}