Связанные статьи:
Что нужно сделать для запуска интеграции по OAuth:
После заключения партнерского приложения разработчик получает:
| Параметр | Описание | Пример | 
| client_id | Строка. Код партнера | myapp324234234234 | 
| application_id | Число. Код приложения | 1 | 
Чтобы получить secret нужно будет вызвать метод UserAPI (Получение secret для интеграции по OAuth):
curl --location --request POST 'https://userapi.mts-link.ru/v3/partner-applications/{applicationId}/reset-secret' \
--header 'x-auth-token: {apiKey}'
где
{ applicationId } - 1
{apiKey} - ключ к UserAPI вашего тестового стенда
Ответ:
{
"data": {
"secret": "{secret}"
}
}
По умолчанию, все OAuth интеграции запрещены, чтобы предотвратить несанкционированный доступ. Администратору нужно явным образом разрешить интеграцию, тогда её смогут использовать другие сотрудники организации.
Разрешить доступ можно через API.
curl --location --request POST 'https://userapi.mts-link.ru/v3/partner-application-clients/{applicationId}/enable' \
--header 'x-auth-token: {apiKey}'
Также администратор может разрешить в ЛК (Организация - Интеграции - OAuth-приожения)

Подробнее:
Необходимо запрашивать минимально необходимый список прав. Например, для выгрузки списка события достаточно доступа userapi_events_read. Ниже подробно перечислены доступы для вызова каждого метода UserAPI.
| Name | Description | 
| userapi_contacts | Полный доступ к контактам | 
| userapi_contacts_read | Доступ к чтению контактов | 
| userapi_courses | Полный доступ к курсам | 
| userapi_courses_read | Доступ на чтение данных курсов | 
| userapi_events | Полный доступ к мероприятиям | 
| userapi_events_read | Доступ на чтение данных мероприятий | 
| userapi_files | Полный доступ к файлам | 
| userapi_files_read | Доступ на чтение данных файлов | 
| userapi_link_chats | Полный доступ к Линк-Чатам | 
| userapi_link_chats_read | Доступ на чтение данных Линк-Чатов | 
| userapi_media_streams | Доступ к подписке на медиа-потоки мероприятия | 
| userapi_organization | Полный доступ к управлению организацией | 
| userapi_organization_read | Доступ на чтение данных организации | 
| userapi_records | Полный доступ к записям мероприятий | 
| userapi_records_read | Доступ на чтение данных записей мероприятия | 
| userapi_statistics | Доступ к статистике | 
| userapi_tests | Полный доступ к тестам | 
| userapi_tests_read | Доступ на чтение данных тестов | 
| userapi_webhooks | Полный доступ к веб-хукам | 
| userapi_webhooks_read | Доступ на чтение данных веб-хуков | 
| № | Method | ApiKey scopes | OAuth scopes | 
| 1 | GET /userapi/brandings | userapi_organization | |
| userapi_organization_read | |||
| 2 | GET /userapi/chats/channel/{channelId} | userapi_link_chats | userapi_link_chats | 
| userapi_link_chats_read | userapi_link_chats_read | ||
| 3 | GET /userapi/chats/channel/{channelId}/messages | userapi_link_chats | userapi_link_chats | 
| userapi_link_chats_read | userapi_link_chats_read | ||
| 4 | POST /userapi/chats/channels/create | userapi_link_chats | userapi_link_chats | 
| 5 | POST /userapi/chats/channels/{channelId}/delete | userapi_link_chats | userapi_link_chats | 
| 6 | POST /userapi/chats/channels/{channelId}/send-message | userapi_link_chats | userapi_link_chats | 
| 7 | POST /userapi/chats/channels/{channelId}/update | userapi_link_chats | userapi_link_chats | 
| 8 | GET /userapi/chats/channels/{channelId}/users | userapi_link_chats | userapi_link_chats | 
| userapi_link_chats_read | userapi_link_chats_read | ||
| 9 | POST /userapi/chats/channels/{channelId}/users/add | userapi_link_chats | userapi_link_chats | 
| 10 | POST /userapi/chats/channels/{channelId}/users/remove | userapi_link_chats | userapi_link_chats | 
| 11 | GET /userapi/chats/channels/{userId} | userapi_link_chats | userapi_link_chats | 
| userapi_link_chats_read | userapi_link_chats_read | ||
| 12 | GET /userapi/chats/organization/members | userapi_link_chats | userapi_link_chats | 
| userapi_link_chats_read | userapi_link_chats_read | ||
| 13 | GET /userapi/chats/teams | userapi_link_chats | userapi_link_chats | 
| userapi_link_chats_read | userapi_link_chats_read | ||
| 14 | POST /userapi/chats/teams/create | userapi_link_chats | userapi_link_chats | 
| 15 | POST /userapi/chats/teams/{teamId}/channels/add | userapi_link_chats | userapi_link_chats | 
| 16 | POST /userapi/chats/teams/{teamId}/channels/remove | userapi_link_chats | userapi_link_chats | 
| 17 | POST /userapi/chats/teams/{teamId}/delete | userapi_link_chats | userapi_link_chats | 
| 18 | POST /userapi/chats/teams/{teamId}/update | userapi_link_chats | userapi_link_chats | 
| 19 | POST /userapi/chats/teams/{teamId}/users/add | userapi_link_chats | userapi_link_chats | 
| 20 | POST /userapi/chats/teams/{teamId}/users/remove | userapi_link_chats | userapi_link_chats | 
| 21 | GET /userapi/contacts/search | userapi_contacts | |
| userapi_contacts_read | |||
| 22 | POST /userapi/contacts/tags/add | userapi_contacts | |
| 23 | PUT /userapi/contacts/{contactId} | userapi_contacts | |
| 24 | DELETE /userapi/contacts/{contactId} | userapi_contacts | |
| 25 | GET /userapi/contacts/{contactId} | userapi_contacts | |
| userapi_contacts_read | |||
| 26 | GET /userapi/contacts/{contactId}/user | userapi_contacts | |
| userapi_contacts_read | |||
| 27 | GET /userapi/converted-records | userapi_records | |
| userapi_records_read | |||
| 28 | POST /userapi/convertedrecords/{convertedRecordId}/cancel | userapi_records | |
| 29 | GET /userapi/courses/{courseId} | userapi_courses | |
| userapi_courses_read | |||
| 30 | GET /userapi/courses/{courseId}/groups | userapi_courses | |
| userapi_courses_read | |||
| 31 | GET /userapi/courses/{courseId}/groups/{groupId} | userapi_courses | |
| userapi_courses_read | |||
| 32 | GET /userapi/courses/{courseId}/groups/{groupId}/statistics | userapi_courses | |
| userapi_courses_read | |||
| 33 | POST /userapi/events | userapi_events | userapi_events | 
| userapi_internal_for_link_chats | |||
| 34 | POST /userapi/events/call | userapi_events | |
| userapi_internal_for_link_chats | |||
| 35 | POST /userapi/events/{eventId}/files | userapi_events | userapi_events | 
| 36 | DELETE /userapi/events/{eventId}/files | userapi_events | |
| 37 | GET /userapi/events/{eventId}/files | userapi_events | userapi_events | 
| userapi_events_read | userapi_events_read | ||
| 38 | DELETE /userapi/events/{eventId}/files/{fileId} | userapi_events | userapi_events | 
| 39 | GET /userapi/events/{eventId}/files/{fileId} | userapi_events | |
| userapi_events_read | |||
| 40 | PUT /userapi/events/{eventId}/files/{fileId} | userapi_events | |
| 41 | POST /userapi/events/{eventId}/invite | userapi_events | userapi_events | 
| 42 | PUT /userapi/events/{eventId}/moderate | userapi_events | |
| 43 | GET /userapi/events/{eventId}/participations | userapi_events | |
| userapi_events_read | |||
| 44 | POST /userapi/events/{eventId}/register | userapi_events | userapi_events | 
| 45 | POST /userapi/events/{eventId}/sessions | userapi_events | userapi_events | 
| userapi_internal_for_link_chats | |||
| 46 | GET /userapi/eventsessions/endless | userapi_events | userapi_events | 
| userapi_events_read | userapi_events_read | ||
| 47 | GET /userapi/eventsessions/endless/activities | userapi_events | userapi_events | 
| userapi_events_read | userapi_events_read | ||
| 48 | GET /userapi/eventsessions/files | userapi_events | |
| userapi_events_read | |||
| 49 | PUT /userapi/eventsessions/{eventSessionId} | userapi_events | userapi_events | 
| 50 | GET /userapi/eventsessions/{eventSessionId} | userapi_events | userapi_events | 
| userapi_events_read | userapi_events_read | ||
| userapi_internal_for_link_chats | |||
| 51 | DELETE /userapi/eventsessions/{eventSessionId} | userapi_events | |
| 52 | GET /userapi/eventsessions/{eventSessionId}/agendas | userapi_events | |
| userapi_events_read | |||
| 53 | POST /userapi/eventsessions/{eventSessionId}/chat | userapi_events | |
| 54 | DELETE /userapi/eventsessions/{eventSessionId}/chat | userapi_events | |
| 55 | GET /userapi/eventsessions/{eventSessionId}/chat | userapi_events | |
| userapi_events_read | |||
| 56 | PUT /userapi/eventsessions/{eventSessionId}/chat/messages/moderate | userapi_events | |
| 57 | GET /userapi/eventsessions/{eventSessionId}/converted-records | userapi_records | |
| userapi_records_read | |||
| 58 | POST /userapi/eventsessions/{eventSessionId}/files | userapi_events | userapi_events | 
| 59 | DELETE /userapi/eventsessions/{eventSessionId}/files | userapi_events | |
| 60 | GET /userapi/eventsessions/{eventSessionId}/files | userapi_events | userapi_events | 
| userapi_events_read | userapi_events_read | ||
| 61 | PUT /userapi/eventsessions/{eventSessionId}/files/{fileId} | userapi_events | |
| 62 | GET /userapi/eventsessions/{eventSessionId}/files/{fileId} | userapi_events | |
| userapi_events_read | |||
| 63 | DELETE /userapi/eventsessions/{eventSessionId}/files/{fileId} | userapi_events | userapi_events | 
| 64 | POST /userapi/eventsessions/{eventSessionId}/invite | userapi_events | userapi_events | 
| userapi_internal_for_link_chats | |||
| 65 | POST /userapi/eventsessions/{eventSessionId}/media-streams/subscribe | userapi_media_streams | |
| 66 | POST /userapi/eventsessions/{eventSessionId}/media-streams/unsubscribe | userapi_media_streams | |
| 67 | GET /userapi/eventsessions/{eventSessionId}/participations | userapi_events | userapi_events | 
| userapi_events_read | userapi_events_read | ||
| 68 | POST /userapi/eventsessions/{eventSessionId}/participations/remove-privacy-data | userapi_events | |
| 69 | GET /userapi/eventsessions/{eventSessionId}/questions | userapi_events | |
| userapi_events_read | |||
| 70 | POST /userapi/eventsessions/{eventSessionId}/questions | userapi_events | |
| 71 | DELETE /userapi/eventsessions/{eventSessionId}/questions | userapi_events | |
| 72 | PUT /userapi/eventsessions/{eventSessionId}/questions/moderate | userapi_events | |
| 73 | PUT /userapi/eventsessions/{eventSessionId}/records | userapi_records | userapi_events | 
| 74 | POST /userapi/eventsessions/{eventSessionId}/records/conversions | userapi_records | |
| 75 | POST /userapi/eventsessions/{eventSessionId}/register | userapi_events | userapi_events | 
| 76 | PUT /userapi/eventsessions/{eventSessionId}/start | userapi_events | |
| userapi_internal_for_link_chats | |||
| 77 | PUT /userapi/eventsessions/{eventSessionId}/stop | userapi_events | |
| userapi_internal_for_link_chats | |||
| 78 | GET /userapi/eventsessions/{eventSessionId}/transcript/list | userapi_events | |
| userapi_events_read | |||
| 79 | POST /userapi/fileSystem/file | userapi_files | userapi_files | 
| 80 | GET /userapi/fileSystem/file/{id} | userapi_files | userapi_files | 
| userapi_files_read | userapi_files_read | ||
| 81 | DELETE /userapi/fileSystem/file/{id} | userapi_files | userapi_files | 
| 82 | GET /userapi/fileSystem/files | userapi_files | userapi_files | 
| userapi_files_read | userapi_files_read | ||
| 83 | GET /userapi/fileSystem/files/converted-record | userapi_records | |
| userapi_records_read | |||
| 84 | POST /userapi/fileSystem/folder | userapi_files | |
| 85 | POST /userapi/groups/{groupId}/invites | userapi_courses | |
| 86 | PUT /userapi/groups/{groupId}/invites/resend | userapi_courses | |
| 87 | PUT /userapi/groups/{groupId}/invites/resend/all | userapi_courses | |
| 88 | GET /userapi/invitation-link/url | userapi_organization | |
| userapi_organization_read | |||
| userapi_internal_for_link_chats | |||
| 89 | POST /userapi/membership/{membershipId}/delete | userapi_organization | |
| 90 | GET /userapi/organization-groups | userapi_organization | |
| userapi_organization_read | |||
| 91 | GET /userapi/organization/courses | userapi_courses | |
| userapi_courses_read | |||
| 92 | GET /userapi/organization/courses/groups | userapi_courses | |
| userapi_courses_read | |||
| 93 | GET /userapi/organization/events/schedule | userapi_events | |
| userapi_events_read | |||
| 94 | GET /userapi/organization/events/{eventId} | userapi_events | |
| userapi_events_read | |||
| 95 | PUT /userapi/organization/events/{eventId} | userapi_events | userapi_events | 
| 96 | DELETE /userapi/organization/events/{eventId} | userapi_events | userapi_events | 
| 97 | PUT /userapi/organization/events/{eventId}/move | userapi_events | |
| 98 | GET /userapi/organization/eventsessions/streamFilesUrls | userapi_records | |
| userapi_records_read | |||
| 99 | GET /userapi/organization/members | userapi_organization | userapi_organization | 
| userapi_organization_read | userapi_organization_read | ||
| userapi_internal_for_link_chats | |||
| 100 | GET /userapi/organization/users/{userId}/statistics | userapi_statistics | |
| 101 | POST /userapi/organizations/invite-users | userapi_organization | |
| userapi_internal_for_link_chats | |||
| 102 | POST /userapi/participations/delete | userapi_events | |
| 103 | PUT /userapi/participations/kick | userapi_events | |
| 104 | PUT /userapi/participations/update | userapi_events | |
| 105 | POST /userapi/partner-application-clients/{applicationId}/disable | userapi_organization | |
| 106 | POST /userapi/partner-application-clients/{applicationId}/enable | userapi_organization | |
| 107 | GET /userapi/partner-application-users | userapi_organization | |
| userapi_organization_read | |||
| 108 | POST /userapi/partner-application-users/remove | userapi_organization | |
| 109 | GET /userapi/partner-applications | userapi_organization | |
| userapi_organization_read | |||
| 110 | POST /userapi/partner-applications/{partnerApplicationId}/reset-secret | userapi_organization | |
| 111 | GET /userapi/profile | profile | profile | 
| 112 | GET /userapi/records | userapi_records | |
| userapi_records_read | |||
| 113 | GET /userapi/records/conversions/{conversionId} | userapi_records | |
| userapi_records_read | |||
| 114 | DELETE /userapi/records/{recordId} | userapi_records | |
| 115 | PUT /userapi/records/{recordId} | userapi_records | |
| 116 | POST /userapi/records/{recordId}/conversions | userapi_records | |
| 117 | POST /userapi/records/{recordId}/share | userapi_records | |
| 118 | GET /userapi/stats/events | userapi_statistics | |
| 119 | GET /userapi/stats/users | userapi_statistics | |
| 120 | GET /userapi/stats/users/visits | userapi_statistics | |
| 121 | POST /userapi/tests | userapi_tests | |
| 122 | GET /userapi/tests/list | userapi_tests | |
| userapi_tests_read | |||
| 123 | PUT /userapi/tests/{testId} | userapi_tests | |
| 124 | DELETE /userapi/tests/{testId} | userapi_tests | |
| 125 | GET /userapi/tests/{testId} | userapi_tests | |
| userapi_tests_read | |||
| 126 | GET /userapi/tests/{testId}/customanswers | userapi_tests | |
| userapi_tests_read | |||
| 127 | GET /userapi/tests/{testId}/results | userapi_tests | |
| userapi_tests_read | |||
| 128 | POST /userapi/tests/{testId}/start | userapi_tests | |
| 129 | POST /userapi/testsessions/{testSessionId}/answers | userapi_tests | |
| 130 | PUT /userapi/testsessions/{testSessionId}/assessanswers | userapi_tests | |
| 131 | PUT /userapi/testsessions/{testSessionId}/stop | userapi_tests | |
| 132 | GET /userapi/timezones | userapi_events | userapi_events | 
| userapi_events_read | userapi_events_read | ||
| 133 | GET /userapi/transcript/{transcriptId} | userapi_events | |
| userapi_events_read | |||
| 134 | PUT /userapi/user/{userId} | userapi_organization | |
| userapi_internal_for_link_chats | |||
| 135 | POST /userapi/users/{userId}/contacts | userapi_contacts | |
| 136 | GET /userapi/users/{userId}/events/schedule | userapi_events | userapi_events | 
| userapi_events_read | userapi_events_read | ||
| 137 | GET /userapi/users/{userId}/tests/stats | userapi_tests | |
| userapi_tests_read | |||
| 138 | GET /userapi/webhooks | userapi_webhooks | |
| userapi_webhooks_read | |||
| userapi_internal_for_link_chats | |||
| 139 | POST /userapi/webhooks/create | userapi_webhooks | |
| userapi_internal_for_link_chats | |||
| 140 | POST /userapi/webhooks/{webhookId}/delete | userapi_webhooks | |
| userapi_internal_for_link_chats | 
Размещаете в вашем приложении кнопку "Подключить МТС Линк". При нажатии пользователя нужно перенаправить на страницу запроса доступа к данным пользователя.
Формат ссылки: https://my.mts-link.ru/authorize?response_type=code
&client_id={clientId из шага 1}
&scope=userapi_events_read+userapi_events_write
&state={не обязательно, значение, которое вернем при обратном редиректе}
Опционально можно передать &redirect_uri=https://example-app.com/callback. Данный параметр указывает на какой url в этот раз отправить обратно, если зарегистрируете у нас более одного приложения.
После авторизации пользователя в МТС Линк и подтверждения им предоставления прав пользователь будет перенаправлен на указанный redirect_url с добавлением параметров code и state (если они его передавали).
?code={code}&state=123
Возможные ошибки:
Тариф клиента не разрешает интеграцию по API
Приложение не разрешено для установки в данной организации
Приложение не найдено
Ваше приложение с использованием полученного code выполняет запрос для получения JWT-токена
curl --location 'https://my.mts-link.ru/api/idp/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={clientId}' \
--data-urlencode 'client_secret={secret}' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code={code}'
Пример ответа
{
"token_type": "Bearer",
"expires_in": 600,
"access_token": "...",
"refresh_token": "..."
}
Некоторые методы UserAPI поддерживают работу одновременно с разными типами ключей, но отличаются заголовки. Оба типа авторизации в API продолжат работать дальше.
для OAuth параметр: --header 'authorization: Bearer {access_token}'
для обычного API ключа: --header 'x-auth-token: {apiKey}'
Пример запроса временных зон:
curl --location --request POST 'https://userapi.mts-link.ru/v3/timezones' \ --header 'authorization: Bearer {access_token}'
где {access_token} - полученное в предыдущем пункте значение.
curl --location 'https://my.mts-link.ru/api/idp/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={clientId}' \
--data-urlencode 'client_secret={secret}' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token={refresh_token}'
API. Profile профиль пользователя (OAuth)
Внутри личного кабинета МТС Линк пользователь видит список подключенных интеграций и может их удалить. При этом токен становится неактивным, все доступы приложения удаляются.
Администратор организации видит сессии пользователей и может при необходимости удалять сессии других пользователей, или запрещать приложение с одновременным удалением сессий сразу для всех пользователей организации.