Skip to main content

Responses to server-side API requests

200 Success

The request is successful, the response will have the following data:

Response object

ParameterTypeNullableDescription
app_idStringThe internal ID of your app. You can see in the the Adapty Dashboard: App Settings -> General tab.
profile_idUUIDAdapty profile ID. You can see it in the Adapty ID field on the Adapty Dashboard -> Profiles -> specific profile page.
customer_user_idStringThe ID of your user in your system. You can see it in the Customer user ID field on the Adapty Dashboard -> Profiles -> specific profile page. It will work only if you identify the users in your mobile app code via Adapty SDK.
total_revenue_usdFloatA float value representing the total revenue in USD earned in the profile.
segment_hashStringInternal parameter.
timestampIntegerResponse time in milliseconds, needs for resolve a race condition.
custom_attributesDictionary

A maximum of 30 custom attributes to the profile are allowed to be set. If you provide the custom_attributes dictionary, you must provide at least one attribute key.

Key: The key must be a string with no more than 30 characters. Only letters, numbers, dashes, points, and underscores allowed

Value: The attribute value must be no more than 30 characters. Only strings and floats are allowed as values, booleans will be converted to floats. Send an empty value or null to delete the attribute.

access_levelsDictionaryProfile Paid Access Level objects. Dictionary where the keys are paid access level identifiers configured by a developer in the Adapty Dashboard. Values are Access level objects. Can be null if the customer has no access levels.
subscriptionsDictionaryDictionary where the keys are vendor product IDs. Values are Subscription objects. Can be null if the customer has no subscriptions.
non_subscriptionsDictionaryDictionary where the keys are vendor product ids. Values are an array of Non-Subscription objects. Can be null if the customer has no purchases.

Response example

{
"data": {
"app_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"profile_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"customer_user_id": "8612ED7C-3477-466D-93AE-1854B8E5FDD5",
"total_revenue_usd": 109.88999999999999,
"segment_hash": "string",
"timestamp": 0,
"custom_attributes": [
{
"key": "string",
"value": "string"
}
],
"access_levels": [
{
"access_level_id": "premium",
"store": "app_store",
"store_product_id": "weekly_8.99",
"store_base_plan_id": "",
"store_transaction_id": "530001802720333",
"store_original_transaction_id": "530001724306018",
"offer": {
"category": "introductory",
"type": "free_trial",
"id": "offer12"
},
"environment": "Production",
"starts_at": "2022-10-12T09:42:50.000000+0000",
"purchased_at": "2022-10-12T09:42:50.000000+0000",
"originally_purchased_at": "2021-10-12T09:42:50.000000+0000",
"expires_at": "2022-10-12T09:42:50.000000+0000",
"renewal_cancelled_at": "2022-10-12T09:42:50.000000+0000",
"billing_issue_detected_at": "2022-10-12T09:42:50.000000+0000",
"is_in_grace_period": true,
"cancellation_reason": "voluntarily_cancelled"
}
],
"subscriptions": [
{
"store": "app_store",
"store_product_id": "weekly_8.99",
"store_base_plan_id": "",
"store_transaction_id": "530001802720333",
"store_original_transaction_id": "530001724306018",
"offer": {
"offer_category": "introductory",
"offer_type": "free_trial",
"offer_id": "offer12"
},
"environment": "Production",
"purchased_at": "2022-10-12T09:42:50.000000+0000",
"originally_purchased_at": "2021-10-12T09:42:50.000000+0000",
"expires_at": "2022-10-12T09:42:50.000000+0000",
"renewal_cancelled_at": "2022-10-12T09:42:50.000000+0000",
"billing_issue_detected_at": "2022-10-12T09:42:50.000000+0000",
"is_in_grace_period": true,
"cancellation_reason": "voluntarily_cancelled"
}
],
"non_subscriptions": [
{
"purchase_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"store": "app_store",
"store_product_id": "weekly_8.99",
"store_base_plan_id": "",
"store_transaction_id": "530001724306018",
"store_original_transaction_id": "530001724306018",
"purchased_at": "2022-10-12T09:42:50.000000+0000",
"environment": "Production",
"is_refund": true,
"is_consumable": true
}
]
}
}

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.

Parameters
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.

Parameters
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.

Parameters
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

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.

Parameters
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_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
}

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.

Parameters
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
}

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
}

401 Unauthorized

The request failed due to missing or incorrect authorization. Check the Authorization page, paying close attention to the Authorization header.

The request also failed because the specified profile wasn’t found.

Body:
ParameterTypeDescription
errorsObject
  • source: (string) Always non_field_errors
  • errors: A description of the error.
error_codeStringShort error name. Always not_authenticated.
status_codeIntegerHTTP status. Always 401.
Response example:
{
"errors": [
{
"source": "non_field_errors",
"errors": [
"Authentication credentials were not provided."
]
}
],
"error_code": "not_authenticated",
"status_code": 401
}

404 Not found

The request failed because the specified profile wasn’t found.

Body
ParameterTypeDescription
errorsObject
  • source: (string) Always non_field_errors
  • errors: A description of the error.
error_codeStringShort error name. Always not_found.
status_codeIntegerHTTP status. Always 404.
Response example
{
"errors": [
{
"source": "non_field_errors",
"errors": [
"Not found."
]
}
],
"error_code": "not_found",
"status_code": 404
}