Skip to main content

Response to server-side API requests: 400: Bad request

billing_issue_detected_at_date_comparison_error

A billing issue happens when there’s a problem during a subscription renewal attempt, so it always occurs after the transaction date (purchased_at).

To resolve this, make sure the billing issue date (billing_issue_detected_at) is later than the transaction date (purchased_at).

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always billing_issue_detected_at
  • errors: A description of the error.
error_codeStringShort error name. Always billing_issue_detected_at_date_comparison_error.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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

A user can’t buy a subscription that has already expired. So, the expires_at date (when the subscription expires) should always be later than the purchased_at date (when the transaction occurred).

To fix this, check these dates and ensure that expires_at is after purchased_at.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always expires_at
  • errors: A description of the error.
error_codeStringShort error name. Always expires_date_error.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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

The request failed because the is_family_shared parameter is set to true, meaning the access level is shared with a family member for free. However, the value parameter of the Price object isn’t set to zero.

If is_family_shared should be true, make sure to set the value parameter of the Price object to 0.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always is_family_shared
  • errors: A description of the error.
error_codeStringShort error name. Always: family_share_price_error.
status_codeIntegerHTTP status. Always 400.

Response example

The profile is not found

{
"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

The request failed because the offer_type parameter is set to free_trial, but the value parameter of the Price object isn’t set to zero.

Another possible reason is that the offer_id parameter was included but left null, even though it can’t be null. In this case, either provide a value for offer_id or remove the parameter entirely.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always offer.type
  • errors: A description of the error.
error_codeStringShort error name. Always: free_trial_price_error.
status_codeIntegerHTTP status. Always 400.

Response example

The profile is not found

{
"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

A grace period is extra time you can give customers to extend their subscription if they couldn’t renew it on time—for instance, if their credit card didn’t go through. This helps keep their settings intact while they resolve any issues. Offering a grace period is optional.

If you do offer a grace period, the expiration date for it (grace_period_expires_at) should be later than the subscription expiration date (expires_at). If not, the grace period expiration time will match the subscription expiration time. In any case, the grace period expiration can’t be earlier than the subscription expiration.

To fix this, make sure the grace period expiration date (grace_period_expires_at) is later than the subscription expiration date (expires_at).

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always grace_period_expires_at
  • errors: A description of the error.
error_codeStringShort error name. Always grace_period_expires_date_error.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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

The start of a grace period counts as a billing issue. So, if the grace period has started (indicated by the grace_period_expires_at parameter being filled in), its start date should be recorded in the billing_issue_detected_at parameter.

To fix this, either set the start of the grace period in billing_issue_detected_at or, if the grace period hasn’t started yet, remove the grace_period_expires_at parameter.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always grace_period_billing_error
  • errors: A description of the error.
error_codeStringShort error name. Always grace_period_billing_error.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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

The request failed because the offer_category parameter has a value other than introductory or offer_type but doesn’t include an offer_id. In this case, either provide an offer_id or remove the offer_category or offer_type from the request.

Another possible reason is that the offer_id parameter was added but left as null, even though it can’t be null. If that’s the case, either add a value for offer_id or remove the parameter entirely.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always offer.category
  • errors: A description of the error.
error_codeStringShort error name. Possible value: missing_offer_id.
status_codeIntegerHTTP status. Always 400.

Response example

The profile is not found

{
"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

The request failed because a trial was provided with a one-time purchase. Unlike subscriptions, one-time purchases can’t have a trial. To fix this, check the offer_type in the Offer object within the One-Time Purchase object. The value for offer_type can’t be free_trial. Either change the offer_type field value or switch to using the Subscription object instead of One-Time Purchase.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always offer.type
  • errors: A description of the error.
error_codeStringShort error name. Always one_time_purchase_trial_error.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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

For prolonged subscriptions, a chain of transactions is created. The original transaction is the first one in this chain, and it links all the following transactions. Each renewal is simply an extension of this original. If the transaction is the first purchase, it serves as its original transaction.

The originally_purchased_at timestamp marks the time of the original purchase, while purchased_at is the time of the current transaction. Because of this, purchased_at can never be earlier than originally_purchased_at; at most, they can be the same for the very first transaction.

The request failed because originally_purchased_at is set to a later date than purchased_at. Make sure it’s earlier or equal to purchased_at.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always originally_purchased_at
  • errors: A description of the error.
error_codeStringShort error name. Always originally_purchased_date_error.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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
}

The request failed because the access level in the request couldn’t be found. Double-check that there are no typos in the access_level_id and that it matches the correct app.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always non_field_errors
  • errors: A description of the error.
error_codeStringShort error name. Possible value: paid_access_level_does_not_exist.
status_codeIntegerHTTP status. Always 404.

Response example

The access level was not found.

{
"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

The request failed because the profile in the request header wasn’t found. Double-check that there are no typos in the profile_id or customer_user_id you entered in the request header, and make sure it’s for the correct app.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always non_field_errors
  • errors: A description of the error.
error_codeStringShort error name. Possible value: profile_does_not_exist.
status_codeIntegerHTTP status. Always 400.

Response example

The profile is not found

{
"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

The request failed because the profile in the request doesn’t match the specified access level. Double-check that the profile ID in the header and the access level ID in the body are correct, and make sure there are no typos.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always non_field_errors
  • errors: A description of the error.
error_codeStringShort error name. Always profile_paid_access_level_does_not_exist.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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

The request failed because the purchase date (purchased_at) is earlier than or equal to the refund date (refunded_at). A refund always happens after a purchase, as it reverses the transaction.

To fix this, check the purchased_at and refunded_at parameters and make sure the refund date is later than the purchase date.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always refunded_at
  • errors: A description of the error.
error_codeStringShort error name. Always refund_date_error.
status_codeIntegerHTTP status. Always 400.

Response example

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

refund_fields_error

The request failed because it either includes cancellation_reason without a refunded_at date, or it has refunded_at without a cancellation_reason.

When a refund is set, both the refund date and reason need to be specified.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always refunded_at
  • errors: A description of the error.
error_codeStringShort error name. Always refund_fields_error.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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

Renewal is a prolongation of a subscription. The user can cancel the subscription prolongation and then again prolong it. The time of both these actions is stored in the renew_status_changed_at parameter. And it can never happen earlier than the transaction itself.

To fix the issue, make sure the renew_status_changed_at is later than the time of the transaction (purchased_at).

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always originally_purchased_at
  • errors: A description of the error.
error_codeStringShort error name. Always originally_purchased_date_error.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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

The request failed because the revoke_at you defined in the request is later than the current access level expires_at parameter. If you want to prolong the access level, use the Grant access level request.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always non_field_errors
  • errors: A description of the error.
error_codeStringShort error name. Always revocation_date_more_than_expiration_date.
status_codeIntegerHTTP status. Always 400.

Response example

  {
"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

In the case of prolonged subscriptions, a chain of subscriptions is generated. The original transaction is the very first transaction in this chain and the chain is linked by it. Other transactions in the chain are prolongations. If the transaction is the very first purchase in the subscription chain, it can be its own original transaction.

Another case is a one-time purchase. It never creates chains as it cannot have prolongations. For it, the store_transaction_id is always the same as the store_original_transaction_id.

Your request failed because the store_transaction_id value for the One-Time Purchase object differs from its store_original_transaction_id . To fix the issue, either make them the same, or change the object - use Subscription instead of the One-Time Purchase.

Body

ParameterTypeDescription
errorsObject
  • source: (string) Always store_transaction_id
  • errors: A description of the error.
error_codeStringShort error name. Always store_transaction_id_error.
status_codeIntegerHTTP status. Always 400.

Response example

{
"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

The request failed because the specified revocation date is in the past. Set revoke_at to a future date or null to revoke access immediately.

Body
ParameterTypeDescription
errorsObject
  • source: (string) Always revoke_at.
  • errors: A description of the error.
error_codeStringShort error name. Always value_error.
status_codeIntegerHTTP status. Always 400.
Response example
{
"errors": [
{
"source": null,
"errors": [
"Must be greater than the current time or null"
]
}
],
"error_code": "value_error",
"status_code": 400
}