При интеграции СБИС с 1С, CRM, интернет-магазином, ERP или собственной информационной системой первый вопрос обычно возникает ещё до работы с контрагентами и документами: как правильно авторизовать внешнее приложение в СБИС?
На практике здесь важно не перепутать несколько разных сущностей: идентификатор приложения, защищённый ключ, сервисный ключ, токен доступа и сессию. Если смешать их в одном месте, интеграция начинает работать нестабильно: токен получают перед каждым запросом, секреты оказываются в Git, а при ошибке авторизации непонятно, какой именно уровень системы нужно проверять.
В актуальной документации Saby для сервисной авторизации внешнего приложения используются
app_client_id, app_secret и secret_key.
По этим данным приложение получает токен доступа, который затем передаётся в API-запросах
через заголовок X-SBISAccessToken.
В этой статье разберём именно серверный сценарий, когда интеграция работает в фоне без постоянного участия пользователя: например, 1С автоматически получает сведения о контрагентах, отправляет документы или синхронизирует данные с СБИС.
Коротко: как устроена авторизация СБИС API
В упрощённом виде цепочка выглядит так:
Внешнее приложение
↓
app_client_id + app_secret + secret_key
↓
POST /oauth/service/
↓
Токен доступа
↓
X-SBISAccessToken: <token>
↓
Saby API
↓
JSON-RPC / API Gateway
↓
Данные и команды
То есть секреты используются для получения токена, а сам токен — для последующих запросов. Бизнес-код приложения не должен каждый раз заново проходить весь процесс получения credentials.
Какие данные нужны для СБИС API
Для сервисной авторизации используются три значения. Их назначение удобно разделять сразу:
| Параметр | Что это | Где используется |
|---|---|---|
app_client_id |
Идентификатор внешнего приложения | При получении токена |
app_secret |
Защищённый ключ приложения | При сервисной авторизации |
secret_key |
Сервисный секретный ключ | При сервисной авторизации |
token |
Полученный токен доступа | В последующих API-запросах |
В интерфейсе Saby эти данные появляются после создания и настройки внешнего приложения. Сам сервисный ключ генерируется системой и может быть выгружен из карточки приложения.
Шаг 1. Создать внешнее приложение в СБИС
Сначала в Saby нужно зарегистрировать внешнюю систему, которая будет обращаться к API. Это важнее, чем кажется: права доступа назначаются именно приложению, а не отдельному HTTP-запросу.
В актуальной инструкции Saby путь выглядит следующим образом:
- Открыть настройки Saby.
- Перейти в раздел безопасности.
- Открыть «Подключения к Saby».
- Добавить внешнее приложение.
- Указать название и описание приложения.
- Настроить разрешённые адреса или IP, если это требуется.
- Включить сервисный доступ.
- Выбрать необходимые права.
- Настроить авторизацию по сервисному ключу.
- Сохранить приложение.
Для production-интеграции лучше сразу использовать принцип минимально необходимых прав. Если сервису требуется только чтение данных контрагентов, не стоит выдавать ему полный доступ ко всем операциям СБИС.
Шаг 2. Настроить права внешнего приложения
Один из наиболее частых вопросов при интеграции — почему авторизация успешна, но конкретная команда API возвращает ошибку доступа.
Причина обычно не в токене. Токен подтверждает, что приложение авторизовано. Отдельно существуют права, которые определяют, что именно этому приложению разрешено делать.
Поэтому диагностику удобно разделять на два уровня:
Уровень 1
Credentials
app_client_id
app_secret
secret_key
↓
Авторизация
↓
Token
Уровень 2
Token + права приложения
↓
Конкретная команда API
↓
Доступ разрешён / запрещён
Это особенно важно для интеграций с 1С: приложение может успешно получить токен, но не иметь права выполнять отдельную операцию с документами или организацией.
Шаг 3. Получить app_client_id, app_secret и secret_key
После настройки приложения в его карточке доступны необходимые параметры. В конфигурации интеграции они будут выглядеть примерно так:
SBIS_APP_CLIENT_ID=...
SBIS_APP_SECRET=...
SBIS_SECRET_KEY=...
Здесь важно не перепутать название переменной с названием параметра API.
Например, мы можем назвать переменную окружения SBIS_SECRET_KEY,
но при формировании HTTP-запроса передать её значение как поле secret_key.
Эти значения нельзя хранить в публичном репозитории, передавать в браузер или выводить в обычный production-лог.
Шаг 4. Получить токен доступа
Для сервисной авторизации Saby указывает endpoint:
POST https://online.saby.ru/oauth/service/
Тело запроса передаётся в JSON и содержит три параметра:
{
"app_client_id": "YOUR_APP_CLIENT_ID",
"app_secret": "YOUR_APP_SECRET",
"secret_key": "YOUR_SECRET_KEY"
}
Полный пример через cURL:
curl -X POST 'https://online.saby.ru/oauth/service/' \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{
"app_client_id": "YOUR_APP_CLIENT_ID",
"app_secret": "YOUR_APP_SECRET",
"secret_key": "YOUR_SECRET_KEY"
}'
При успешной авторизации Saby возвращает данные, необходимые для дальнейшего обмена.
В актуальной документации сервисной авторизации токен представлен полем token.
{
"token": "YOUR_ACCESS_TOKEN"
}
В некоторых материалах и сценариях Saby встречается термин access_token.
В конкретной реализации интеграции ориентируйтесь на фактический формат ответа используемого
endpoint и актуальную документацию Saby.
Шаг 5. Передать токен в API-запросе
Полученный токен используется в заголовке:
X-SBISAccessToken: YOUR_ACCESS_TOKEN
Для API Gateway запросы выполняются по HTTP, а данные команды передаются в формате JSON-RPC. В текущей документации API Gateway используется endpoint версии API, например:
https://online.saby.ru/apigate/v1/
Базовая структура JSON-RPC-запроса:
{
"jsonrpc": "2.0",
"method": "METHOD.NAME",
"params": {},
"id": 1
}
Таким образом, минимальный HTTP-запрос состоит из endpoint, заголовка авторизации и JSON-RPC тела.
Первый тестовый запрос
После получения токена полезно сначала проверить сам контур авторизации, не подключая сразу бизнес-методы, документы и 1С.
curl -X POST 'https://online.saby.ru/apigate/v1/' \
-H 'Content-Type: application/json; charset=utf-8' \
-H 'X-SBISAccessToken: YOUR_ACCESS_TOKEN' \
-d '{
"jsonrpc": "2.0",
"method": "APIGatewayObject.Echo",
"params": {
"message": "Hello world!"
},
"id": 1
}'
Если тестовый вызов проходит, можно переходить к конкретному методу API. Это хороший диагностический приём: сначала проверяем транспорт и авторизацию, затем права, затем параметры бизнес-команды.
JSON-RPC: что находится внутри API-запроса
Для интегратора важно не смешивать две вещи: авторизацию и бизнес-команду. Заголовок сообщает API, каким токеном авторизован запрос, а тело описывает, какую команду нужно выполнить.
| Поле | Назначение |
|---|---|
jsonrpc |
Версия протокола JSON-RPC |
method |
Имя вызываемой команды |
params |
Параметры конкретной команды |
id |
Идентификатор запроса |
Ответ также содержит JSON-структуру. При успешном выполнении результат находится в
result, а при ошибке сервер возвращает объект error с кодом,
сообщением и дополнительными данными.
{
"jsonrpc": "2.0",
"id": 1,
"result": {}
}
Ошибочный ответ концептуально выглядит так:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": 123,
"message": "Ошибка",
"details": "Подробное описание",
"data": "ErrorType"
}
}
Сервисная и интерактивная авторизация — в чём разница
Saby поддерживает разные сценарии авторизации. Для backend-интеграции чаще всего нужен сервисный сценарий, но его нельзя автоматически применять к пользовательскому входу.
| Сценарий | Подход | Участие пользователя |
|---|---|---|
| Фоновый обмен 1С ↔ СБИС | Сервисная авторизация | Не требуется |
| CRM ↔ СБИС | Сервисная авторизация | Не требуется |
| Серверная синхронизация документов | Сервисная авторизация | Не требуется |
| Пользователь входит в Saby через внешний сайт | Интерактивный OAuth 2 | Требуется |
Интерактивный сценарий нужен тогда, когда приложение должно работать от имени пользователя и получить его согласие через браузер. Для серверного обмена 1С с СБИС обычно нет смысла заставлять пользователя регулярно проходить такой процесс.
Где хранить ключи СБИС в Symfony
В Symfony-проекте credentials лучше отделить от исходного кода приложения. Минимальный вариант — переменные окружения:
SBIS_APP_CLIENT_ID=...
SBIS_APP_SECRET=...
SBIS_SECRET_KEY=...
В конфигурации приложения эти значения можно передавать в сервис авторизации. В production вместо обычного файла окружения можно использовать секретное хранилище инфраструктуры, если оно доступно в проекте.
Особенно важно не делать так:
final class SbisClient
{
private string $secretKey = 'very-secret-value';
}
И не добавлять реальные credentials в fixtures, README, тестовые конфигурации или примеры, которые затем попадут в публичный репозиторий.
Как разделить SbisAuthClient и SbisApiClient
Для небольшой интеграции можно начать с одного класса, но в production-коде удобнее разделить получение токена и выполнение API-команд.
final class SbisAuthClient
{
public function getToken(): string
{
// POST /oauth/service/
// app_client_id + app_secret + secret_key
}
}
final class SbisApiClient
{
public function call(string $method, array $params): array
{
// X-SBISAccessToken
// JSON-RPC request
}
}
Тогда бизнес-сервис не знает, как именно получается токен. Он работает с API-клиентом, а тот уже решает задачу авторизации.
CompanyService
↓
SbisApiClient
↓
TokenProvider
↓
Saby
Это особенно полезно, когда интеграция постепенно растёт: сначала нужны контрагенты, затем документы, ЭДО, статусы, события и другие команды API.
Не нужно получать новый токен перед каждым запросом
Плохая архитектура выглядит так:
API request
↓
получить token
↓
выполнить запрос
↓
получить token
↓
следующий запрос
Так делать не стоит. Авторизацию нужно выделить в отдельный компонент, который умеет переиспользовать действующие данные авторизации и получать новые только тогда, когда это действительно необходимо.
В документации Saby для сервисной авторизации указано ограничение: одновременно для приложения может быть открыто не более пяти активных сессий. При создании новой сессии сверх лимита самая старая завершается автоматически.
Поэтому массовое создание новых авторизаций из каждого worker или каждого HTTP-запроса — плохая идея ещё и с точки зрения эксплуатации.
Пять параллельных запросов — важный нюанс для интеграции
В документации API Saby отдельно указано ограничение на количество параллельных потоков: при большом числе одновременных вызовов система может ограничивать выполнение или блокировать сессию пользователя.
Поэтому если интеграция работает через очередь, недостаточно просто поставить
Messenger или другой worker pool и увеличить количество consumers.
Параллелизм запросов к Saby нужно контролировать.
Queue
├── Worker 1 ──→ Saby
├── Worker 2 ──→ Saby
├── Worker 3 ──→ Saby
├── Worker 4 ──→ Saby
└── Worker 5 ──→ Saby
controlled concurrency
Для больших обменов это лучше учитывать на уровне архитектуры, а не пытаться исправить проблему после появления блокировок.
Что делать, если токен перестал работать
Ошибку авторизации не стоит сразу трактовать как «СБИС не работает». Нужно определить, на каком этапе произошёл сбой.
| Симптом | Что проверить первым |
|---|---|
| Не получается получить токен | app_client_id, app_secret, secret_key |
| Токен получен, но API его не принимает | Заголовок X-SBISAccessToken и endpoint |
| Авторизация успешна, метод запрещён | Права внешнего приложения |
| Работает вручную, не работает на сервере | IP/адрес приложения, окружение, secrets |
| После увеличения worker появились проблемы | Параллелизм и количество активных сессий |
| API отвечает ошибкой JSON-RPC | method, params, id и формат запроса |
Почему не стоит смешивать 401, права и ошибки метода
При диагностике удобно разделить ошибки на несколько уровней:
HTTP / transport
↓
Авторизация
↓
Права приложения
↓
JSON-RPC
↓
Параметры метода
↓
Бизнес-данные
Например, если credentials неверные, бессмысленно проверять структуру params.
Если авторизация успешна, но конкретный раздел запрещён, изменение JSON-RPC тоже не решит проблему.
И наоборот: корректный токен не исправит неправильное имя метода.
Retry: как повторять запросы правильно
Сетевые ошибки и временная недоступность внешнего API — нормальная часть интеграции. Но retry должен быть ограниченным и управляемым.
Business Command
↓
Saby API
│
├── success ─────────→ result
│
└── temporary error
↓
retry #1
↓
retry #2
↓
retry #3
↓
DLQ
Для production-интеграции полезно иметь как минимум:
- ограниченное число повторов;
- exponential backoff;
- разделение временных и постоянных ошибок;
- журналирование request id и технического контекста;
- очередь проблемных сообщений;
- идемпотентность бизнес-операций.
Сам токен при этом не должен автоматически обновляться на любую ошибку API. Если проблема в параметрах метода или правах, бесконечное получение новых токенов только усложнит диагностику.
Идемпотентность важнее, чем кажется
Представим интеграцию, которая отправляет документ из 1С в СБИС. Запрос завершился сетевым timeout. Интеграция не знает, был ли документ принят на стороне Saby.
Если просто повторить операцию, можно получить дубль или другое нежелательное состояние. Поэтому для критичных операций нужно хранить внешний идентификатор, состояние обмена и результат последней попытки.
1С
↓
Integration Service
↓
Operation ID
↓
Saby API
↓
┌─────────────────────────┐
│ success │
│ temporary error → retry │
│ permanent error → DLQ │
└─────────────────────────┘
СБИС API и 1С: типовая архитектура
Если интеграция небольшая, 1С может напрямую обращаться к API. Но по мере роста количества методов появляется отдельный интеграционный слой.
┌──────────────────┐
│ 1С:ERP │
└────────┬─────────┘
│
↓
┌────────────────────────────┐
│ Integration Layer │
│ │
│ Auth │
│ API Client │
│ Mapping │
│ Validation │
│ Retry │
│ Idempotency │
│ Logging │
└────────────┬───────────────┘
│
↓
┌────────────────────────────┐
│ Saby API │
└────────────────────────────┘
В такой модели 1С не нужно знать детали авторизации и повторных запросов. Она передаёт бизнес-команду интеграционному сервису, а тот отвечает за технический контур.
Когда достаточно прямой интеграции 1С → СБИС
Прямой вызов из 1С может быть вполне разумным решением, если обмен небольшой:
- одна конфигурация 1С;
- небольшое количество методов;
- небольшой объём данных;
- нет сложной очереди;
- нет нескольких внешних систем;
- ошибки можно обрабатывать внутри прикладного решения.
Отдельный Integration Layer начинает окупаться, когда появляется несколько источников данных, много параллельных операций, сложные правила повторов, централизованное логирование или необходимость подключить к тому же СБИС API CRM, сайт и другие сервисы.
СБИС API: авторизация через Symfony HttpClient
В Symfony техническую часть можно реализовать через стандартный HTTP-клиент. Упрощённый вариант получения токена:
use Symfony\Contracts\HttpClient\HttpClientInterface;
final class SbisAuthClient
{
public function __construct(
private HttpClientInterface $httpClient,
private string $appClientId,
private string $appSecret,
private string $secretKey,
) {
}
public function getToken(): string
{
$response = $this->httpClient->request(
'POST',
'https://online.saby.ru/oauth/service/',
[
'json' => [
'app_client_id' => $this->appClientId,
'app_secret' => $this->appSecret,
'secret_key' => $this->secretKey,
],
],
);
$data = $response->toArray();
return $data['token'];
}
}
Это именно технический пример. В production-коде вокруг него нужны обработка HTTP-ошибок, проверка структуры ответа, логирование без секретов и механизм повторного использования полученного токена.
Symfony API client для JSON-RPC
Следующий слой отвечает уже за выполнение команд:
final class SbisApiClient
{
public function __construct(
private HttpClientInterface $httpClient,
private SbisTokenProvider $tokenProvider,
) {
}
public function call(string $method, array $params): array
{
$token = $this->tokenProvider->getToken();
$response = $this->httpClient->request(
'POST',
'https://online.saby.ru/apigate/v1/',
[
'headers' => [
'X-SBISAccessToken' => $token,
'Content-Type' => 'application/json; charset=utf-8',
],
'json' => [
'jsonrpc' => '2.0',
'method' => $method,
'params' => $params,
'id' => 1,
],
],
);
return $response->toArray();
}
}
В реальном проекте значение id лучше генерировать или передавать из контекста
конкретной операции, а URL версии API вынести в конфигурацию.
Как не засветить токен в логах
Типичная ошибка при отладке HTTP-интеграции — логировать весь request вместе с заголовками.
Если в лог попадёт X-SBISAccessToken, технический журнал превращается в источник
секретов.
В логах лучше сохранять:
- название операции;
- внутренний идентификатор сообщения;
- метод API;
- HTTP status;
- код ошибки Saby;
- время выполнения;
- номер попытки.
Не следует сохранять в обычном техническом логе:
app_secret;secret_key;- полный access token;
- пароли;
- полный HTTP request с секретными заголовками.
Типичные ошибки при настройке СБИС API
1. Перепутали app_secret и secret_key
Оба значения выглядят как секретные строки, поэтому их легко поменять местами. В конфигурации лучше использовать явные имена и не объединять их в одну переменную.
2. Токен получили, но забыли заголовок
X-SBISAccessToken: YOUR_ACCESS_TOKEN
Получить token недостаточно. Он должен передаваться в последующих запросах.
3. Дали приложению слишком много прав
Для интеграции лучше заранее определить необходимые операции и выдать только соответствующий доступ. Это одновременно упрощает безопасность и диагностику.
4. Получают токен перед каждым вызовом
Авторизация должна быть отдельным компонентом, а не частью каждой бизнес-операции. Иначе при большом обмене можно быстро получить лишнюю нагрузку и проблемы с сессиями.
5. Сразу запускают много параллельных workers
Для API-интеграции количество параллельных запросов нужно контролировать. Очередь сама по себе не гарантирует безопасную нагрузку на внешний API.
6. На любую ошибку запускают повторную авторизацию
Ошибка метода, ошибка прав и временный сетевой сбой — разные ситуации. Перед retry нужно определить класс ошибки.
7. Хранят секреты в .env.local, который случайно попадает в архив
Локальный файл удобен для разработки, но production credentials должны управляться контролируемым механизмом секретов.
Безопасность: минимальный checklist
Как выглядит production-контур
Для корпоративной интеграции мы обычно разделяем бизнес-логику и технический обмен. Тогда архитектура получается примерно такой:
┌─────────────────────┐
│ 1С:ERP │
└──────────┬──────────┘
│
↓
┌──────────────────────────────────┐
│ Integration Layer │
│ │
│ Business Commands │
│ Mapping │
│ Validation │
│ │ │
│ ↓ │
│ SbisApiClient │
│ │ │
│ ├── TokenProvider │
│ ├── Retry │
│ ├── Idempotency │
│ └── Logging │
└────────────────┬─────────────────┘
│
↓
┌──────────────────────────────────┐
│ Saby API │
└──────────────────────────────────┘
Если к системе подключаются CRM, сайт, WMS или другие приложения, они могут использовать тот же интеграционный слой. Это позволяет не реализовывать авторизацию и retry отдельно в каждом клиенте.
СБИС API + 1С: что происходит при реальной операции
Возьмём практический сценарий: 1С должна получить данные контрагента по ИНН.
1. 1С получает ИНН
↓
2. Отправляет команду Integration Layer
↓
3. Integration Layer получает действующий token
↓
4. Формирует JSON-RPC
↓
5. Отправляет запрос в Saby
↓
6. Проверяет HTTP / API / business result
↓
7. Преобразует ответ в внутренний DTO
↓
8. Возвращает данные в 1С
Такой подход особенно полезен, если СБИС — не единственный внешний источник. Внутри системы можно иметь единый интерфейс получения сведений о контрагенте, а конкретные API СБИС, ФНС, Контур или других сервисов скрыть за адаптерами.
Авторизация — только первый этап интеграции
После того как token успешно получен, начинается основная работа: конкретные команды, преобразование данных, обработка ошибок и синхронизация состояния.
Поэтому полноценная интеграция обычно состоит из нескольких уровней:
Authentication
↓
API Client
↓
DTO / Mapping
↓
Business Service
↓
Queue
↓
Retry / DLQ
↓
Database / 1C
Чем больше систем участвует в обмене, тем сильнее становится ценность отдельного Integration Layer.
Минимальный MVP интеграции СБИС API
Если нужно не строить сразу большую платформу, а быстро запустить первую рабочую интеграцию, достаточно следующего набора:
Что делать после первого успешного запроса
Не стоит сразу переносить в production код из тестового cURL-примера. После успешной авторизации желательно проверить весь технический контур:
- секреты вынесены из кода;
- токен не попадает в логи;
- права приложения минимальны;
- авторизация отделена от бизнес-логики;
- есть обработка HTTP-ошибок;
- есть обработка JSON-RPC
error; - retry ограничен;
- контролируется параллелизм;
- критичные операции защищены от дублей;
- есть мониторинг интеграции.
Итог: правильная схема авторизации СБИС API
┌──────────────────────────┐
│ Внешнее приложение │
└────────────┬─────────────┘
│
│ app_client_id
│ app_secret
│ secret_key
↓
┌──────────────────────────┐
│ POST /oauth/service/ │
└────────────┬─────────────┘
│
↓
┌──────────────────────────┐
│ access token │
└────────────┬─────────────┘
│
│ X-SBISAccessToken
↓
┌──────────────────────────┐
│ Saby API │
│ JSON-RPC │
└────────────┬─────────────┘
│
↓
┌──────────────────────────┐
│ Контрагенты / документы │
│ ЭДО / данные / операции │
└──────────────────────────┘
Сам процесс авторизации несложный. Сложность начинается в production: нужно правильно хранить секреты, ограничивать права, не создавать лишние сессии, контролировать параллельность, обрабатывать временные ошибки и не допускать дублей при повторной доставке сообщений.
Для небольшой интеграции достаточно аккуратного API-клиента. Для корпоративного обмена 1С ↔ СБИС разумно выделить Integration Layer, который будет отвечать за авторизацию, mapping, очереди, retry, idempotency и журналирование.