Неофициальный API клиент lknpd.nalog.ru ("Мой Налог")
Позволяет автоматизировать отправку информации о доходах для самозанятых, получать информацию о созданных чеках и удалять их. Поддерживается аутентификация по ИНН и паролю, а также по номеру телефона.
С помощью composer
$ composer require shoman4eg/moy-nalogТакже Вам понадобится реализация виртуального пакета psr/http-client-implementation, например (рекомендуется):
Symfony
$ composer require symfony/http-clientИли Guzzle
$ composer require guzzlehttp/guzzle// Необходимо выставить часовой пояс для корректного формирования дат в чеках
// Можно установить с помощью функции date_default_timezone_set
date_default_timezone_set('Europe/Kaliningrad');
// или через класс DateTimeImmutable, с нужным часовым поясом, перед созданием чека
$operationTime = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Kaliningrad'))use Shoman4eg\Nalog\ApiClient;
use Shoman4eg\Nalog\Http\ClientConfigurator;
use Shoman4eg\Nalog\Service\Generator\DeviceIdGenerator;
use Shoman4eg\Nalog\Service\Generator\StaticIdStrategy;
use Shoman4eg\Nalog\Service\Generator\IdStrategyInterface;
// Клиент с настройками по умолчанию
$apiClient = ApiClient::create();
// Создание клиента с прокси
$proxiedHttpClient = new \GuzzleHttp\Client([
'proxy' => 'tcp://12.34.56.78:3128',
]);
$apiClient = ApiClient::createWithCustomClient($proxiedHttpClient);
// или
$apiClient = new ApiClient(clientConfigurator: new ClientConfigurator($proxiedHttpClient));
// Изменить DeviceId. По умолчанию используется PlatformIdStrategy где deviceId генерируется на основе платформы.
$apiClient = new ApiClient(deviceIdGenerator: new DeviceIdGenerator()); // По умолчанию
// Полезно использовать, если вы обслуживаете несколько самозанятых
$apiClient = new ApiClient(deviceIdGenerator: new DeviceIdGenerator(new StaticIdStrategy('example id')))
// Так же возможно написать свою реализацию
$apiClient = new ApiClient(deviceIdGenerator: new DeviceIdGenerator(new class implements IdStrategyInterface {
public function getId(): string
{
return md5('example id');
}
}));При аутентификации с помощью методов createNewAccessToken (по ИНН и паролю) или createNewAccessTokenByPhone (по номеру телефона) , вместе с токеном доступа (accessToken), возвращается также токен обновления (refreshToken) с неограниченным сроком действия. Сохраните оригинальный ответ этих методов и используйте повторно в методе authenticate.
При повторном использовании методов
createNewAccessTokenиcreateNewAccessTokenByPhone, предыдущий accessToken становится недействительным.
Если Вам нужно восстановить пароль от сервиса "Мой налог", это возможно сделать только через "Личный кабинет налогоплательщика". Аккаунты на обоих сервисах одинаковые.
use Shoman4eg\Nalog\ApiClient;
$apiClient = ApiClient::create();
try {
// Запрос accessToken
$accessToken = $apiClient->createNewAccessToken($username, $password);
} catch (\Shoman4eg\Nalog\Exception\Domain\UnauthorizedException $e) {
var_dump($e->getMessage());
}
// Аутентификация с помощью accessToken
$apiClient->authenticate($accessToken);Вариант аутентификации по номеру телефона происходит в 2 шага:
- Запросите SMS с кодом подтверждения на номер телефона и сохраните возвращённый challengeToken;
- Обменяйте номер телефона, challengeToken и код подтверждения на accessToken.
Внимание: запрос нового кода подтверждения возможен только если предыдущий код истёк (2 минуты), или по предыдущему коду произошла успешная аутентификация. Повторная отправка выпущенного кода подтверждения невозможна, только одновременно с созданием нового.
use Shoman4eg\Nalog\ApiClient;
$apiClient = ApiClient::create();
try {
$phoneChallengeResponse = ApiClient::createPhoneChallenge('79000000000');
/**
* $phoneChallengeResponse = [
* 'challengeToken' => '00000000-0000-0000-0000-000000000000',
* 'expireDate' => '2022-11-24T00:20:19.135436Z',,
* 'expireIn' => 120,
* ];
*/
} catch (\Shoman4eg\Nalog\Exception\Domain\UnauthorizedException $e) {
var_dump($e->getMessage());
}
// Сохраните $phoneChallengeResponse['challengeToken']. Он потребуется Вам на втором шаге.use Shoman4eg\Nalog\ApiClient;
$apiClient = ApiClient::create();
try {
// Запрос accessToken
$accessToken = $apiClient->createNewAccessTokenByPhone(
'79000000000', // Номер телефона
'00000000-0000-0000-0000-000000000000', // challengeToken
'123456' // Код из СМС
);
} catch (\Shoman4eg\Nalog\Exception\Domain\UnauthorizedException $e) {
var_dump($e->getMessage());
}
// Аутентификация с помощью accessToken
$apiClient->authenticate($accessToken);$name = 'Предоставление информационных услуг #970/2495'; // Наименование
$amount = 1800.30; // Стоимость в рублях
$quantity = 1; // Количество
$operationTime = new DateTimeImmutable('2020-12-31 12:12:00'); // Дата продажи
// Создание чека
$createdIncome = $apiClient->income()->create(
$name,
$amount,
$quantity,
$operationTime
);
// UUID чека для операций запроса данных чека или его отмены
$receiptUuid = $createdIncome->getApprovedReceiptUuid();$items = [
new \Shoman4eg\Nalog\DTO\IncomeServiceItem(
'Предоставление информационных услуг #970/2495', // Наименование
1800.30, // Стоимость
1 // Количество
),
new \Shoman4eg\Nalog\DTO\IncomeServiceItem(
'Предоставление информационных услуг #971/2495',
900,
2
),
// И так далее...
];
// Дата продажи
$operationTime = new DateTimeImmutable('2020-12-31 12:12:00');
// Создание чека
$createdIncome = $apiClient->income()->createMultipleItems(
$items,
$operationTime
);
// UUID чека для операций запроса данных чека или его отмены
$receiptUuid = $createdIncome->getApprovedReceiptUuid();$name = 'Предоставление информационных услуг #970/2495'; // Наименование
$amount = 1800.30; // Стоимость
$quantity = 1; // Количество
$operationTime = new DateTimeImmutable('2020-12-31 12:12:00'); // Дата продажи
// По умолчанию физ. лицо без указания контактных данных (INDIVIDUAL)
$client = new \Shoman4eg\Nalog\DTO\IncomeClient();
// Или физ. лицо с указанием контактных данных (INDIVIDUAL)
$client = new \Shoman4eg\Nalog\DTO\IncomeClient(
'+79009000000',
'Вася Пупкин',
\Shoman4eg\Nalog\Enum\IncomeType::INDIVIDUAL,
'390000000000' // ИНН физ. лица (12 символов)
);
// Или юр. лицо (ИП, ООО и т.п.) (LEGAL_ENTITY)
$client = new \Shoman4eg\Nalog\DTO\IncomeClient(
null,
'ИП Вася Пупкин Валерьевич',
\Shoman4eg\Nalog\Enum\IncomeType::LEGAL_ENTITY,
'7700000000' // ИНН юр. лица (10 символов)
);
// Или иностранная организация (FOREIGN_AGENCY)
$client = new \Shoman4eg\Nalog\DTO\IncomeClient(
null,
'Facebook Inc.',
\Shoman4eg\Nalog\Enum\IncomeType::FOREIGN_AGENCY,
'9909000000' // ИНН иностранной организации (10 символов)
);
// Создание чека
$createdIncome = $apiClient->income()->create(
$name,
$amount,
$quantity,
$operationTime,
$client
);
// UUID чека для операций запроса данных чека или его отмены
$receiptUuid = $createdIncome->getApprovedReceiptUuid();// Получить список чеков
$incomes = $apiClient->income()->list();
// Фильтрация
$incomes = $apiClient->income()->list(
from: new DateTimeImmutable('31.12.2025 23:59:59'), // начало периода для поиска (по умолчанию: null)
to: new DateTimeImmutable('31.12.2025 23:59:59'), // конец периода для поиска (по умолчанию: null)
offset: 10, // смещение результатов для пагинации (по умолчанию: 0)
limit: 25, // Количество результатов (по умолчанию: 100)
buyerType: \Shoman4eg\Nalog\Enum\BuyerType::PERSON, // Тип покупателя (по умолчанию: null)
receiptType: \Shoman4eg\Nalog\Enum\ReceiptType::REGISTERED, // Тип чека (по умолчанию: null)
sortBy: \Shoman4eg\Nalog\Api\Income::SORT_OPERATION_TIME_ASC // Сортировка (по умолчанию: \Shoman4eg\Nalog\Api\Income::SORT_OPERATION_TIME_DESC)
);
// Возможные значения фильтрации:
$buyerType = \Shoman4eg\Nalog\Enum\BuyerType::PERSON; // физлицо
$buyerType = \Shoman4eg\Nalog\Enum\BuyerType::COMPANY; // юрлицо
$buyerType = \Shoman4eg\Nalog\Enum\BuyerType::FOREIGN_AGENCY; // Иностранная организация
$receiptType = \Shoman4eg\Nalog\Enum\ReceiptType::REGISTERED; // Действителен
$receiptType = \Shoman4eg\Nalog\Enum\ReceiptType::CANCELLED; // Аннулирован
$sortBy = Shoman4eg\Nalog\Api\Income::SORT_OPERATION_TIME_ASC; // Дата: сначала старые
$sortBy = Shoman4eg\Nalog\Api\Income::SORT_OPERATION_TIME_DESC; // Дата: сначала новые
$sortBy = Shoman4eg\Nalog\Api\Income::SORT_TOTAL_AMOUNT_ASC; // Стоимость: по возрастанию
$sortBy = Shoman4eg\Nalog\Api\Income::SORT_TOTAL_AMOUNT_DESC; // Стоимость: по убыванию// UUID чека
$receiptUuid = "20hykdxbp8";
// Получить ссылку на чек для печати
$receipt = $apiClient->receipt()->printUrl($receiptUuid);
// Получить данные по чеку в JSON формате
$receipt = $apiClient->receipt()->json($receiptUuid);// UUID чека
$receiptUuid = "20hykdxbp8";
// Причина отмены: "Чек выдан ошибочно"
$comment = \Shoman4eg\Nalog\Enum\CancelCommentType::CANCEL;
// Причина отмены: "Возврат денежных средств"
$comment = \Shoman4eg\Nalog\Enum\CancelCommentType::REFUND;
// Код партнёра (по умолчанию: null)
$partnerCode = null;
// Дата совершения возврата (по умолчанию: now)
$operationTime = new \DateTimeImmutable('now');
// Дата запроса отмены чека (по умолчанию: now)
$requestTime = new \DateTimeImmutable('now');
// Отмена чека
$incomeInfo = $apiClient->income()->cancel(
$receiptUuid,
$comment,
$operationTime,
$requestTime,
$partnerCode
);$apiClient->authenticate($accessToken);
$userInfo = $apiClient->user()->get();$apiClient->authenticate($accessToken);
$userInfo = $apiClient->tax()->get();$apiClient->authenticate($accessToken);
$userInfo = $apiClient->tax()->payments();$apiClient->authenticate($accessToken);
$userInfo = $apiClient->tax()->history();Проблема #47: Не приходят СМС для получения токена
- Описание: Проблемы с получением СМС-кода для авторизации
- Решение: Проблема связана с API сервиса nalog.ru, временная недоступность сервиса отправки СМС
Проблема #22: Авторизация по телефону или внешним ключам
- Описание: Невозможность авторизоваться без пароля (только по номеру телефона)
- Решение: Для получения пароля нужно восстановить его через веб-интерфейс "Мой налог"
Проблема #49: Токен истекает несмотря на наличие RefreshToken
- Описание: RefreshToken не срабатывает для получения нового токена
- Настоящая причина: Токен API "Мой налог" привязывается к конкретному IP-адресу или Device ID, с которого он был сгенерирован
- Решение: Токен нужно генерировать на нужном окружении. Токен, созданный с одного IP-адреса/Device ID, не будет работать с другого IP-адреса/Device ID (Точно сказать не могу, можно попробовать использовать в обоих окружениях StaticIdStrategy) чтобы удостовериться, что Refresh token привязывается к IP с которого сделан запрос.
- Рекомендация: Генерировать токен на том же сервере, с которого будут выполняться API-запросы
Проблема #21: Ошибка Could not resolve host: lknpd.nalog.ru
- Описание: Невозможность резолва DNS для API сервера
- Решение: Временная проблема на стороне сервера или DNS. Проверить настройки DNS на сервере
Проблема #38: No HTTPlug clients found
- Описание: Ошибка "No HTTPlug clients found"
- Решение: Установить любой psr/http-client-implementation совместимый клиент, например
symfony/http-client
- Описание: Одна из причин может быть проблема с тем, что на одном сервере обрабатывается множество пользоавтелей и DeviceID одинаковый для всех. Так же можно получить ответ:
{
"code": "authentication.failed",
"message": "Устройство <GENERATED DEVICE ID > для пользователя <INN> не может быть зарегистрировано/обновлено. Так как устройство заблокировано. Причина: Согласно обращению УОК о неправомерном доступе к ЛК",
"additionalInfo": {}
}- Решение: Использовать другой Device id, к примеру так:
use Shoman4eg\Nalog\ApiClient;
use Shoman4eg\Nalog\Service\Generator\DeviceIdGenerator;
$apiClient = new ApiClient(deviceIdGenerator: new DeviceIdGenerator(new StaticIdStrategy('<example id>')))Статья на Habr: Автоматизация для самозанятых: как интегрировать налог с IT проектом
Реализация на JS: alexstep/moy-nalog
Changelog: A complete changelog
Если этот проект поможет Вам сократить время разработки, вы можете угостить меня чашкой кофе :)
The MIT License (MIT). Please see License File for more information.