Ответ на запросы к серверному API: 400: Bad request

billing_issue_detected_at_date_comparison_error

Проблема с оплатой возникает при неудачной попытке продления подписки, поэтому она всегда происходит после даты транзакции (purchased_at).

Убедитесь, что дата проблемы с оплатой (billing_issue_detected_at) позже даты транзакции (purchased_at).

Тело ответа

ПараметрТипОписание
errorsObject
  • source: (string) Всегда billing_issue_detected_at
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда billing_issue_detected_at_date_comparison_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "billing_issue_detected_at",
      "errors": [
        "billing_issue_detected_at must be later than purchased_at."
      ]
    }
  ],
  "error_code": "billing_issue_detected_at_date_comparison_error",
  "status_code": 400
}

expires_date_error

Пользователь не может купить подписку, которая уже истекла. Поэтому дата expires_at (когда истекает подписка) всегда должна быть позже даты purchased_at (когда произошла транзакция).

Чтобы исправить ошибку, проверьте эти даты и убедитесь, что expires_at позже purchased_at.

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда expires_at
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда expires_date_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "expires_at",
      "errors": [
        "expires_at must be later than purchased_at."
      ]
    }
  ],
  "error_code": "expires_date_error",
  "status_code": 400
}

family_share_price_error

Запрос завершился ошибкой, потому что параметр is_family_shared установлен в true, то есть уровень доступа предоставляется члену семьи бесплатно. При этом параметр value объекта Price не равен нулю.

Если is_family_shared должен быть true, убедитесь, что параметр value объекта Price установлен в 0.

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда is_family_shared
  • errors: Описание ошибки.
error_codeStringКороткое название ошибки. Всегда: family_share_price_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

Профиль не найден

{
  "errors": [
    {
      "source": "is_family_shared",
      "errors": [
        "If is_family_shared is true, price.value must be 0."
      ]
    }
  ],
  "error_code": "family_share_price_error",
  "status_code": 400
}

free_trial_price_error

Запрос завершился ошибкой, поскольку параметр offer_type имеет значение free_trial, но параметр value объекта Price не равен нулю.

Ещё одна возможная причина: параметр offer_id был указан, но оставлен null, хотя он не может быть null. В этом случае либо укажите значение для offer_id, либо удалите параметр полностью.

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда offer.type
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда: free_trial_price_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

Профиль не найден

{
  "errors": [
    {
      "source": "offer_type",
      "errors": [
        "If offer_type is 'free_trial', price.value must be 0."
      ]
    }
  ],
  "error_code": "free_trial_price_error",
  "status_code": 400
}

grace_period_expires_date_error

Льготный период — это дополнительное время, которое вы можете дать пользователям для продления подписки, если они не успели это сделать вовремя, например из-за проблем с оплатой картой. Это позволяет сохранить их настройки, пока они разбираются с ситуацией. Предоставлять льготный период необязательно.

Если льготный период предусмотрен, дата его окончания (grace_period_expires_at) должна быть позже даты окончания подписки (expires_at). В противном случае время окончания льготного периода совпадёт со временем окончания подписки. В любом случае льготный период не может истекать раньше, чем подписка.

Чтобы исправить ошибку, убедитесь, что дата окончания льготного периода (grace_period_expires_at) позже даты окончания подписки (expires_at).

Body

ParameterTypeDescription
errorsObject
  • source: (string) Всегда grace_period_expires_at
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда grace_period_expires_date_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "grace_period_expires_at",
      "errors": [
        "grace_period_expires_at must be later or equal to expires_at."
      ]
    }
  ],
  "error_code": "grace_period_expires_date_error",
  "status_code": 400
}

grace_period_billing_error

Начало льготного периода считается проблемой с выставлением счёта. Поэтому если льготный период начался (на это указывает заполненный параметр grace_period_expires_at), его дата начала должна быть записана в параметр billing_issue_detected_at.

Чтобы исправить ошибку, либо укажите дату начала льготного периода в billing_issue_detected_at, либо, если льготный период ещё не начался, удалите параметр grace_period_expires_at.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Всегда grace_period_billing_error
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда grace_period_billing_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "grace_period_billing_error",
      "errors": [
        "If grace_period_expires_at is specified, billing_issue_detected_at must also be specified."
      ]
    }
  ],
  "error_code": "grace_period_billing_error",
  "status_code": 400
}

missing_offer_id

Запрос завершился ошибкой, потому что параметр offer_category имеет значение, отличное от introductory или offer_type, но при этом не содержит offer_id. В таком случае нужно либо указать offer_id, либо убрать offer_category или offer_type из запроса.

Другая возможная причина: параметр offer_id добавлен, но задан как null, хотя он не может быть null. В этом случае нужно либо указать значение для offer_id, либо полностью убрать этот параметр.

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда offer.category
  • errors: Описание ошибки.
error_codeStringКороткое название ошибки. Возможное значение: missing_offer_id.
status_codeIntegerHTTP-статус. Всегда 400.

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

Профиль не найден

{
  "errors": [
    {
      "source": "offer_category",
      "errors": [
        "offer_id must be specified for all offer types except 'introductory'."
      ]
    }
  ],
  "error_code": "missing_offer_id",
  "status_code": 400
}

one_time_purchase_trial_error

Запрос завершился ошибкой, так как к разовой покупке был привязан пробный период. В отличие от подписок, разовые покупки не поддерживают пробный период. Чтобы исправить это, проверьте значение offer_type в объекте Offer внутри объекта One-Time Purchase. Значение offer_type не может быть free_trial. Измените значение поля offer_type или используйте объект Subscription вместо One-Time Purchase.

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда offer.type
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда one_time_purchase_trial_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "offer.type",
      "errors": [
        "One-time purchase cannot have a trial."
      ]
    }
  ],
  "error_code": "one_time_purchase_trial_error",
  "status_code": 400
}

originally_purchased_date_error

Для продлённых подписок формируется цепочка транзакций. Первая транзакция в этой цепочке называется исходной и связывает все последующие. Каждое продление является расширением этой исходной транзакции. Если транзакция является первой покупкой, она сама выступает своей исходной транзакцией.

Временная метка originally_purchased_at фиксирует момент исходной покупки, а purchased_at — момент текущей транзакции. Поэтому purchased_at никогда не может быть раньше originally_purchased_at; в крайнем случае они совпадают — для самой первой транзакции.

Запрос завершился с ошибкой, потому что originally_purchased_at указан позже, чем purchased_at. Убедитесь, что это значение меньше или равно purchased_at.

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда originally_purchased_at
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда originally_purchased_date_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "originally_purchased_at",
      "errors": [
        "originally_purchased_at must be earlier than or equal to purchased_at."
      ]
    }
  ],
  "error_code": "originally_purchased_date_error",
  "status_code": 400
}

Запрос завершился ошибкой, потому что указанный в запросе уровень доступа не найден. Проверьте, нет ли опечаток в access_level_id, и убедитесь, что он соответствует нужному приложению.

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда non_field_errors
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Возможное значение: paid_access_level_does_not_exist.
status_codeIntegerHTTP-статус. Всегда 404.

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

Уровень доступа не найден.

{
  "errors": [
    {
      "source": "non_field_errors",
      "errors": [
        "Paid access level `premium` does not exist"
      ]
    }
  ],
  "error_code": "paid_access_level_does_not_exist",
  "status_code": 400
}

profile_does_not_exist

Запрос завершился ошибкой, потому что профиль из заголовка запроса не найден. Проверьте, нет ли опечаток в profile_id или customer_user_id, указанных в заголовке запроса, и убедитесь, что они относятся к правильному приложению.

Тело

ПараметрТипОписание
errorsObject
  • source: (string) Всегда non_field_errors
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Возможное значение: profile_does_not_exist.
status_codeIntegerHTTP-статус. Всегда 400.

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

Профиль не найден

{
  "errors": [
    {
      "source": "non_field_errors",
      "errors": [
        "Profile not found"
      ]
    }
  ],
  "error_code": "profile_does_not_exist",
  "status_code": 400
}

profile_paid_access_level_does_not_exist

Запрос завершился с ошибкой, потому что профиль в запросе не соответствует указанному уровню доступа. Убедитесь, что ID профиля в заголовке и ID уровня доступа в теле запроса указаны верно, и проверьте наличие опечаток.

Тело ответа

ПараметрТипОписание
errorsObject
  • source: (string) Всегда non_field_errors
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда profile_paid_access_level_does_not_exist.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "non_field_errors",
      "errors": [
        "Profile `478b2e7f-d557-4b8b-9c5f-cbd46fc2dee2` has no `premium` access level"
      ]
    }
  ],
  "error_code": "profile_paid_access_level_does_not_exist",
  "status_code": 400
}

refund_date_error

Запрос завершился с ошибкой, поскольку дата покупки (purchased_at) оказалась раньше или равна дате возврата (refunded_at). Возврат всегда происходит после покупки, так как является её отменой.

Чтобы исправить ошибку, проверьте параметры purchased_at и refunded_at и убедитесь, что дата возврата позже даты покупки.

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда refunded_at
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда refund_date_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "refunded_at",
      "errors": [
        "refunded_at must be later than purchased_at."
      ]
    }
  ],
  "error_code": "refund_date_error",
  "status_code": 400
}

refund_fields_error

Запрос завершился ошибкой, поскольку в нём указан cancellation_reason без даты refunded_at, либо refunded_at без cancellation_reason.

При установке возврата средств необходимо указать и дату, и причину возврата.

Тело ответа

ПараметрТипОписание
errorsObject
  • source: (string) Всегда refunded_at
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда refund_fields_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "refunded_at",
      "errors": [
        "refunded_at and cancellation_reason=refund must be specified together."
      ]
    }
  ],
  "error_code": "refund_fields_error",
  "status_code": 400
}

renew_status_changed_date_error

Продление — это пролонгация подписки. Пользователь может отменить автопродление, а затем снова включить его. Время обоих этих действий сохраняется в параметре renew_status_changed_at и не может быть раньше самой транзакции.

Чтобы исправить ошибку, убедитесь, что renew_status_changed_at позже времени транзакции (purchased_at).

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда originally_purchased_at
  • errors: Описание ошибки.
error_codeStringКороткое название ошибки. Всегда originally_purchased_date_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "renew_status_changed_at",
      "errors": [
        "renew_status_changed_at must be later than purchased_at."
      ]
    }
  ],
  "error_code": "renew_status_changed_date_error",
  "status_code": 400
}

revocation_date_more_than_expiration_date

Запрос завершился ошибкой, потому что указанный в запросе параметр revoke_at позже текущего значения expires_at для данного уровня доступа. Если вы хотите продлить уровень доступа, используйте запрос Предоставление уровня доступа.

Body

ПараметрТипОписание
errorsObject
  • source: (string) Всегда non_field_errors
  • errors: Описание ошибки.
error_codeStringКороткое название ошибки. Всегда revocation_date_more_than_expiration_date.
status_codeIntegerHTTP-статус. Всегда 400.

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

  {
  "errors": [
    {
      "source": "revoke_at",
      "errors": [
        "Revocation date (2029-08-29 09:33:42+00:00) is more than current expiration date (2028-08-29 09:33:42+00:00)"
      ]
    }
  ],
  "error_code": "revocation_date_more_than_expiration_date",
  "status_code": 400
}

store_transaction_id_error

В случае продлевающихся подписок формируется цепочка транзакций. Исходная транзакция — это самая первая транзакция в этой цепочке, и все остальные транзакции связаны через неё. Остальные транзакции в цепочке являются продлениями. Если транзакция является самой первой покупкой в цепочке подписок, она может быть своей собственной исходной транзакцией.

Другой случай — разовая покупка. Она никогда не создаёт цепочек, так как не может иметь продлений. Для неё store_transaction_id всегда совпадает с store_original_transaction_id.

Ваш запрос завершился с ошибкой, потому что значение store_transaction_id объекта Разовая покупка отличается от его store_original_transaction_id. Чтобы исправить это, либо сделайте их одинаковыми, либо измените объект — используйте Подписку вместо Разовой покупки.

Тело

ПараметрТипОписание
errorsObject
  • source: (string) Всегда store_transaction_id
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда store_transaction_id_error.
status_codeIntegerHTTP-статус. Всегда 400.

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

{
  "errors": [
    {
      "source": "store_transaction_id",
      "errors": [
        "store_transaction_id must be equal to store_original_transaction_id for purchase."
      ]
    }
  ],
  "error_code": "store_transaction_id_error",
  "status_code": 400
}

value_error

Запрос завершился ошибкой, поскольку указанная дата отзыва находится в прошлом. Установите revoke_at на будущую дату или передайте null, чтобы немедленно отозвать доступ.

Body
ПараметрТипОписание
errorsObject
  • source: (string) Всегда revoke_at.
  • errors: Описание ошибки.
error_codeStringКраткое название ошибки. Всегда value_error.
status_codeIntegerHTTP-статус. Всегда 400.
Пример ответа
{
    "errors": [
        {
            "source": null,
            "errors": [
                "Must be greater than the current time or null"
            ]
        }
    ],
    "error_code": "value_error",
    "status_code": 400
}