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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always billing_issue_detected_at_date_comparison_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always expires_date_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always: family_share_price_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always: free_trial_price_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always grace_period_expires_date_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always grace_period_billing_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Possible value: missing_offer_id . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always one_time_purchase_trial_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always originally_purchased_date_error . |
status_code | Integer | HTTP 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
}
paid_access_level_does_not_exist
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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Possible value: paid_access_level_does_not_exist . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Possible value: profile_does_not_exist . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always profile_paid_access_level_does_not_exist . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always refund_date_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always refund_fields_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always originally_purchased_date_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always revocation_date_more_than_expiration_date . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always store_transaction_id_error . |
status_code | Integer | HTTP 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
Parameter | Type | Description |
---|---|---|
errors | Object |
|
error_code | String | Short error name. Always value_error . |
status_code | Integer | HTTP 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
}