Устаревшие спецификации серверного API

Базовый URL: https://api.adapty.io/api/v1/sdk

Авторизация

Вы просматриваете гайд по устаревшему серверному API. Для актуальной версии обратитесь к Server-side API V2 и Руководству по миграции на Server-side API V2.

Каждый запрос к API должен быть подписан секретным ключом.

При вызове API:

  • Необходимо добавлять заголовок Authorization со значением “Api-Key {secret_token}” (без кавычек) к каждому запросу, например Api-Key secret_live_BEHrYLTr.ce5zuDEWz06lFRNiaJC8mrLtL8fUwswD
  • Используйте JSON-payload в теле запроса для POST и PATCH запросов
  • Все запросы должны содержать заголовок Content-Type: application/json

Работа с customer user ID

Вы просматриваете гайд для устаревшего серверного API. Актуальная версия доступна в разделе Server-side API V2 и Руководство по миграции на Server-side API V2.

Большинство запросов к серверному API поддерживают передачу customer_user_id в качестве параметра URL. Это позволяет легко запрашивать и обновлять данные в Adapty, не сохраняя profile_id Adapty. В большинстве случаев customer_user_id следует передавать как есть, без каких-либо изменений. Однако если ваш customer_user_id содержит зарезервированные символы URI, например /, ?, +, его нужно передавать в закодированном виде. Используйте кодировку Base64URL (не обычный Base64). Так все специальные символы будут закодированы, а Adapty декодирует их при получении. Чтобы сообщить Adapty, что customer_user_id закодирован, передайте GET-параметр is_user_id_base64url_encoded=1. Обратите внимание: если передать параметр is_user_id_base64url_encoded=1 без фактического кодирования, вернётся ошибка валидации 400. Кодировать customer_user_id нужно только в том случае, если вы передаёте его как часть URL-пути. Если customer_user_id передаётся внутри JSON-тела запроса (например, при создании профиля), кодировать его не нужно.

## Don't encode
customer_user_id = '123' # GET: /profiles/123/
customer_user_id = 'abc' # GET: /profiles/abc/
customer_user_id = '3c410419-9959-447a-84b5-be7cb6a308d9' # GET: /profiles/3c410419-9959-447a-84b5-be7cb6a308d9/

## Base64URL encode
customer_user_id = '123+456' # GET: /profiles/MTIzKzQ1Ng==/?is_user_id_base64url_encoded=1
customer_user_id = 'abc/def' # GET: /profiles/YWJjL2RlZg==/?is_user_id_base64url_encoded=1
customer_user_id = '012?012' # GET: /profiles/MDEyPzAxMg==/?is_user_id_base64url_encoded=1

Запросы

Продление/предоставление подписки пользователю

Вы просматриваете гайд для устаревшего серверного API. Актуальная версия доступна в следующих запросах:

  • Set Transaction: Добавление деталей транзакции с предоставлением доступа.
  • Grant Access Level: Добавление или продление доступа без транзакции.
  • Revoke Access Level: Сокращение или отзыв доступа без транзакции.
POST: /profiles/{profile_id_or_customer_user_id}/paid-access-levels/{access_level}/grant/

Параметры пути:

ParamTypeRequiredNullableDescription
profile_id_or_customer_user_idstrAdapty profile ID или внутренний ID разработчика
access_levelstrID (slug) платного уровня доступа. Найдите его в дашборде Adapty

Параметры запроса:

ParamTypeRequiredNullableDescription
expires_atISO 8601 date✅* см. нижеДата окончания подписки
duration_daysint✅* см. нижеДополнительные дни к текущей подписке**
is_lifetimebool✅* см. нижеЕсли установлено значение true, пользователь получит пожизненный доступ навсегда
starts_atISO 8601 dateЕсли время начала действия относится к будущему, его можно передать. Если указаны время начала и период, период будет отсчитываться от указанного времени
vendor_product_idstrПри публикации транзакции укажите ID продукта, который инициирует продление подписки. Если вы предоставляете уровень доступа без транзакции, пропустите этот параметр — по умолчанию будет использован adapty_server_side_product.
base_plan_idstrID базового плана в Google Play Store или ID цены в Stripe.
vendor_original_transaction_idstrID исходной транзакции в цепочке продлений подписки в среде вендора.
vendor_transaction_idstr

ID транзакции в среде вендора.

Если значение совпадает с vendor_original_transaction_id или если vendor_original_transaction_id отсутствует, Adapty считает это первой покупкой подписки. Если значение отличается от vendor_original_transaction_id, Adapty считает покупку продлением подписки.

storestrСтор, в котором пользователь приобрёл продукт, например app_store и play_store; может быть кастомным. По умолчанию — adapty
introductory_offer_typestrТип introductory offer. Доступные значения: free_trial, pay_as_you_go и pay_up_front.
pricefloat

Цена подписки/покупки для сохранения в транзакции.

Первая покупка подписки с нулевой ценой считается бесплатным пробным периодом, а продление с нулевой ценой — бесплатным продлением подписки.

Если вы указываете цену, укажите также price_locale.

price_localestrВалюта транзакции в трёхбуквенном формате. По умолчанию используется USD.
proceedsfloatВыручка (цена за вычетом комиссии стора) подписки/покупки для сохранения в транзакции.
is_sandboxboolБулево значение, указывающее, была ли покупка совершена в песочнице или в продакшн-среде.

Есть три способа предоставить пользователям подписку. Поэтому необходимо задать хотя бы один из параметров: is_lifetime, expires_at или duration_days. Если задано несколько параметров, приоритет имеет is_lifetime=true, затем expires_at, и наконец duration_days. Поскольку всю обработку платежей выполняет Apple/Google, Adapty не может управлять этим процессом или влиять на него. Поэтому при использовании duration_days для активной подписки помните: пользователь всё равно будет списан в нужный день. Например, у пользователя есть ежемесячная подписка, и следующее списание запланировано на 5 апреля. Вы добавляете 7 дней, но пользователь всё равно будет списан 5 апреля! Лучше использовать duration_days для пользователей, которые никогда не подписывались, или для отписавшихся. В этом случае отправной точкой будет день предоставления доступа.

Транзакция

Если указаны все параметры vendor_product_id, vendor_transaction_id и store, Adapty создаёт и сохраняет запись о транзакции, которая учитывается в графиках (Revenue, MRR, Subscriptions) — при условии, что транзакция с такими параметрами ещё не существует (например, созданная в результате покупки на iOS). Если указан параметр price, он привязывается к этой транзакции.

На данный момент такой тип транзакции не генерирует события профиля, не влияет на статус подписки пользователя и не отображается в Event Feed. Также учтите, что эти транзакции влияют на биллинг, поскольку учитываются в MTR.

Пример запроса:

{
    "starts_at": "2020-01-15T15:10:36.517975+0000",
    "expires_at": "2020-02-15T15:10:36.517975+0000",
    "vendor_product_id": "basic_subscription_1_month",
    "vendor_transaction_id": "1000000630116569",
    "store": "app_store",
    "introductory_offer_type": null
}

Пример ответа:

{
  "data": {
    "app_id": "ff90dd2e-e7f2-454b-9d86-071036a284fe",
    "profile_id": "77112400-89f1-4465-b9c9-5437e58c6688",
    "customer_user_id": "[email protected]",
    "paid_access_levels": {
      "premium": {
        "id": "premium",
        "is_active": true,
        "is_lifetime": false,
        "expires_at": "2023-03-29T15:30:34.000000+0000",
        "starts_at": null,
        "will_renew": false,
        "vendor_product_id": "adapty_server_side_product",
        "base_plan_id": "premium_autorenewing",
        "vendor_transaction_id": "1000000630116569",
        "vendor_original_transaction_id": "1000000625263604",
        "store": "adapty",
        "activated_at": "2020-03-26T16:24:19.497674+0000",
        "renewed_at": "2020-03-26T16:24:19.497674+0000",
        "unsubscribed_at": null,
        "billing_issue_detected_at": null,
        "is_in_grace_period": false,
        "active_introductory_offer_type": "free_trial",
        "active_promotional_offer_type": null,
        "active_promotional_offer_id": null,
        "cancellation_reason": null
      }
    },
    "subscriptions": {
      "com.adapty.premium.monthly": {
        "is_active": false,
        "is_lifetime": false,
        "expires_at": "2020-02-21T16:30:34.000000+0000",
        "starts_at": null,
        "will_renew": false,
        "vendor_product_id": "com.adapty.premium.monthly",
        "base_plan_id": "monthly_autorenewing",
        "vendor_transaction_id": "1000000630116569",
        "vendor_original_transaction_id": "1000000625263604",
        "store": "app_store",
        "activated_at": "2020-02-10T19:14:02.000000+0000",
        "renewed_at": "2020-02-21T16:25:34.000000+0000",
        "unsubscribed_at": "2020-02-21T16:30:34.000000+0000",
        "billing_issue_detected_at": "2020-02-21T16:30:34.000000+0000",
        "is_in_grace_period": false,
        "active_introductory_offer_type": null,
        "active_promotional_offer_type": null,
        "active_promotional_offer_id": null,
        "cancellation_reason": "voluntarily_cancelled",
        "is_sandbox": true
      },
      "com.adapty.premium.weekly": {
        "is_active": false,
        "is_lifetime": false,
        "expires_at": "2020-02-10T19:32:00.000000+0000",
        "starts_at": null,
        "will_renew": true,
        "vendor_product_id": "com.adapty.premium.weekly",
        "base_plan_id": "weekly_autorenewing",
        "vendor_transaction_id": "1000000625265713",
        "vendor_original_transaction_id": "1000000625263604",
        "store": "app_store",
        "activated_at": "2020-02-10T19:14:02.000000+0000",
        "renewed_at": "2020-02-10T19:29:00.000000+0000",
        "unsubscribed_at": null,
        "billing_issue_detected_at": null,
        "is_in_grace_period": false,
        "active_introductory_offer_type": null,
        "active_promotional_offer_type": null,
        "active_promotional_offer_id": null,
        "cancellation_reason": null,
        "is_sandbox": true
      },
      "basic_subscription_unlimited": {
        "is_active": true,
        "is_lifetime": false,
        "expires_at": "2021-02-27T11:00:30.000000+0000",
        "starts_at": null,
        "will_renew": false,
        "vendor_product_id": "basic_subscription_unlimited",
        "base_plan_id": "basic_prepaid",
        "vendor_transaction_id": "1000000632277988",
        "vendor_original_transaction_id": "1000000632277988",
        "store": "app_store",
        "activated_at": "2020-02-27T11:00:30.000000+0000",
        "renewed_at": null,
        "unsubscribed_at": null,
        "billing_issue_detected_at": null,
        "is_in_grace_period": false,
        "active_introductory_offer_type": null,
        "active_promotional_offer_type": null,
        "active_promotional_offer_id": null,
        "cancellation_reason": null,
        "is_sandbox": true
      }
    },
    "non_subscriptions": null
  }
}

Подробнее об ответах читайте в разделе Объекты API.

Отзыв подписки у пользователя

Вы просматриваете гайд для устаревшего серверного API. Для последней версии обратитесь к запросу Revoke Access Level, который позволяет как сократить, так и отозвать уровень доступа без транзакции.

POST: /profiles/{profile_id_or_customer_user_id}/paid-access-levels/{access_level}/revoke/

Параметры пути:

ПараметрТипОбязательныйNullableОписание
profile_id_or_customer_user_idstrID профиля Adapty или внутренний ID разработчика
access_levelstrID (slug) платного уровня доступа. Найдите его в дашборде Adapty

Параметры запроса:

ParamTypeRequiredNullableDescription
is_refundboolБыла ли подписка отозвана в связи с возвратом средств
Отзывает подписку пользователя, устанавливая unsubscribed_at в текущее время, а expires_at — в максимальное из текущего starts_at и текущего времени (чтобы expires_at не оказалось меньше starts_at). Если с этим платным уровнем доступа связана транзакция, срок её истечения также обновляется до нового значения expires_at. Если is_refund равно true, транзакция помечается как возврат, а выручка обнуляется.

Валидация покупки в Stripe, предоставление уровня доступа пользователю и импорт истории транзакций из Stripe

POST: /api/v1/sdk/purchase/stripe/token/validate/

Этот запрос должен использовать другой Content-Type: Content-Type: application/vnd.api+json'

Параметры запроса:

ParamTypeRequiredNullableDescription
customer_user_idstrВнутренний ID пользователя в системе разработчика
stripe_tokenstrТокен объекта Stripe, представляющего уникальную покупку. Может быть токеном Stripe Subscription (sub_XXX) или Payment Intent (pi_XXX).

Пример запроса:

curl
--location 'https://api.adapty.io/api/v1/sdk/purchase/stripe/token/validate/' \
--header 'Content-Type: application/vnd.api+json' \
--header 'Authorization: Api-Key <PUBLIC_OR_PRIVATE_KEY' \
--data-raw '{
  "data": {
    "type": "stripe_receipt_validation_result",
    "attributes": {
        "customer_user_id": "<CUSTOMER_USER_ID>",
        "stripe_token": "sub_1OM8brJTlbIG45BdDRFOHWAU"
    }
  }
}'

Проверяет покупку по переданному токену Stripe, используя учётные данные Stripe из App Settings дашборда Adapty. Если покупка действительна, история транзакций импортируется из Stripe в профиль Adapty с указанным customer_user_id. Если профиля с таким customer_user_id не существовало — он будет создан.

В процессе генерируются события профиля, а импортированные транзакции учитываются в MTR.

Получение информации о пользователе

Вы просматриваете гайд по устаревшему серверному API. Для последней версии обратитесь к запросу Get profile.

GET: /profiles/{profile_id_or_customer_user_id}/

Параметры пути:

ParamTypeRequiredNullableDescription
profile_id_or_customer_user_idstrAdapty profile ID или внутренний ID разработчика

Пример ответа такой же, как для Продления/предоставления подписки пользователю. Чтобы получить расширенный ответ, добавьте ключ “extended” с любым значением в параметры запроса (Query Params). Это работает только для GET-запросов.

СвойствоТипОбязательноеNullableОписание
created_atISO 8601 dateДата создания профиля, обычно совпадает с датой установки
emailstrEmail пользователя
phone_numberstrНомер телефона пользователя
att_statusstr
first_namestrИмя пользователя
last_namestrФамилия пользователя
usernamestrИмя пользователя (никнейм)
genderstrПол пользователя
birthdayISO 8601 dateДата рождения пользователя
idfastrИдентификатор для рекламодателей (IDFA), назначаемый Apple устройству пользователя.
idfvstrИдентификатор для вендоров (IDFV) — код, присваиваемый всем приложениям одного разработчика и общий для всех его приложений на устройстве.
advertising_idstrAdvertising ID — уникальный идентификатор операционной системы Android, который рекламодатели могут использовать для однозначной идентификации пользователя.
appsflyer_idstrAppsFlyer ID — идентификатор, автоматически создаваемый AppsFlyer при каждой новой установке приложения.
amplitude_user_idstrСвойство Amplitude User ID и свойство External User ID в OneSignal должны быть заданы, чтобы данные сообщений для этого устройства отслеживались.
amplitude_device_idstrAmplitude Device ID, поступающий непосредственно с устройств пользователей.
mixpanel_user_idstrUser ID из Mixpanel.
appmetrica_profile_idstrID профиля пользователя из AppMetrica.
appmetrica_device_idstrDevice ID из AppMetrica.
facebook_anonymous_idstrFacebook Anonymous ID.

Создание пользователя

Вы просматриваете гайд по устаревшему серверному API. Актуальная версия — в запросе Create profile.

POST: /profiles/

Параметры запроса:

ПараметрТипОбязательныйNullableОписание
customer_user_idstr

Пример запроса:

{
    "customer_user_id": "123456"
}

Ответ аналогичен GET-запросу (параметр extended здесь не работает).

Также можно задать атрибуты пользователя так же, как в методе PATCH.

Задать атрибут пользователя

Вы просматриваете гайд для устаревшей версии серверного API. Для актуальной версии обратитесь к запросу Обновить профиль.

PATCH: /profiles/{profile_id_or_customer_user_id}/

Параметры пути:

ПараметрТипОбязательныйNullableОписание
profile_id_or_customer_user_idstrAdapty profile ID или внутренний ID разработчика

Параметры запроса:

ParamTypeRequiredNullableDescription
ip_countrystrКод страны в двухбуквенном формате, например US.
emailstr
phone_numberstr
first_namestr
last_namestr
genderstrПол пользователя
birthdaydateДата в формате YYYY-MM-DD, например 1990-10-31.
Чтобы задать пользовательские атрибуты, передайте их в словаре custom_attributes. Для профиля можно задать не более 10 пользовательских атрибутов. В качестве значений допустимы только строки и числа с плавающей точкой; булевы значения будут автоматически преобразованы в числа с плавающей точкой.
ParamTypeRequiredNullableDescription
:-------------------:---------:-------:-------:-----------------------------------------------------------
attribute_keystrДопустимы только буквы, цифры, дефисы, точки и символы подчёркивания. Длина ключа атрибута не должна превышать 30 символов.
attribute_valuestr|floatДлина значения атрибута не должна превышать 30 символов. Передайте пустое значение или null, чтобы удалить атрибут.
{
    "phone_number": "+18003330000",
    "custom_attributes": {
        "grade": 10,
        "favorite_topic": "sports"
    }
}

Ответ аналогичен GET-запросу (параметр extended здесь не работает).

Удаление данных пользователя

Вы просматриваете гайд по устаревшему серверному API. Для последней версии обратитесь к запросу Удалить профиль.

DELETE /profiles/{profile_id_or_customer_user_id}/delete

Параметры пути:

ParamTypeRequiredNullableDescription
profile_id_or_customer_user_idstrAdapty profile ID или внутренний ID разработчика
Вызов этого эндпоинта удаляет профиль пользователя и все связанные с ним данные, делая их недоступными для клиента. История профиля, связанная с удалённым профилем, будет отвязана, а интеграционные события, ранее отправленные в интеграции, будут удалены из ленты событий.

Если другой профиль совершит покупку с того же устройства с тем же Apple ID (или при восстановлении подписки), история профиля будет переназначена новому профилю, а интеграционные события будут отправлены повторно. Обратите внимание, что этот эндпоинт не поддерживает массовое удаление, поэтому каждый запрос обрабатывается отдельно. При работе с большим количеством пользователей рекомендуется выполнять запросы параллельно.