---
title: "Read the settings"
method: GET
path: "/v1/projects/{project}/retention"
tags: ["Revenue Recovery"]
---

# Read the settings

`GET /v1/projects/{project}/retention`

## Request

- Base URL: `https://api.subscriby.net`
- URL: `https://api.subscriby.net/v1/projects/{project}/retention`
- Auth: HTTP bearer

```bash
curl https://api.subscriby.net/v1/projects/7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13/retention \
  -H "Authorization: Bearer sbt_..."
```

The grace window with the ladder it implies in words, the digest switch, the cancellation question, the three offers with the coupons they carry, and the two nurture windows: `checkout_stall_hours` (how long a checkout may stay open with no settled charge before the hourly sweep counts it as stalled and the stalled-checkout sequences start; 1 to 24, 1 by default) and `trial_notice_days` (how many days before a trial without a card ends its trial-ending sequences start; 1 to 14, 3 by default; a shorter trial enrols at its start). The row is created with the defaults on the first read, so a project never answers `404` here.

### Two fields that are easy to misread

**`offers_available` is the owner's plan, not a setting.** It is `true` on Growth and with the Revenue Recovery Addon. The three offer fields are stored whatever it says; the cancellation screen reads them only while it is `true`.

**`ladder` is derived from `grace_days`.** It is the sentence the dashboard and the bot show for the window, in the token holder's language; write `grace_days` and read `ladder` back.

## Path parameters

- `project` string, uuid, required

## Response `200`

The settings with the ladder in words and whether the offers are available.

- object
  - `data` RetentionSettingsResource, required: A project's Revenue Recovery settings: how long a failed renewal keeps access, the notice ladder that follows in words, whether the daily digest is sent, what the cancellation screen asks, which of the three offers it makes, how long a checkout may stay open before it counts as stalled, and how many days before a trial without a card ends its sequence starts.
    - `project_id` string, required: The project the settings belong to.
    - `grace_days` integer, required: How many days a failed renewal keeps access while the gateway retries, 0 to 30. `0` pauses access at the failure.
    - `ladder` string, required: The grace window and its notices in words, as the dashboard and the bot say them.
    - `digest_enabled` boolean, required: Whether the owner gets one message a day with the failures, reminders, pauses and recoveries, only on a day something happened.
    - `cancel_feedback_enabled` boolean, required: Whether the cancellation screen asks the member why before the offer.
    - `checkout_stall_hours` integer, required: How many hours a checkout may stay open with no settled charge before the hourly sweep counts it as stalled and the stalled-checkout sequences start, 1 to 24.
    - `trial_notice_days` integer, required: How many days before a trial without a card ends its trial-ending sequences start, 1 to 14. A trial shorter than that enrols at its start.
    - `offers_available` boolean, required: Whether the project owner's plan includes the offers (Growth or the Revenue Recovery Addon). The three offer settings are stored either way and ignored by the screen without it.
    - `offer_pause_enabled` boolean, required: Whether a cancelling member on Stripe or PayPal is offered one billing cycle on hold.
    - `offer_discount_coupon` object, nullable: The coupon applied to a cancelling member's renewals where Stripe can carry it, or `null` for no discount offer.
      - `id` string, required: The coupon's id.
      - `code` string, required: The coupon's code.
    - `offer_return_coupon` object, nullable: The coupon handed to a cancelling member on every payment method, to come back with, or `null` for no return coupon.
      - `id` string, required: The coupon's id.
      - `code` string, required: The coupon's code.
    - `updated_at` string, nullable, required: When the settings last changed, ISO 8601.

## Other responses

- `401`: `AUTHENTICATION_REQUIRED`: the request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an `sbt_test_` token on production).
- `403`: `TOKEN_MISSING_ABILITY`: the token is valid but does not carry the ability this endpoint requires; `error.context.required_ability` names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers `FORBIDDEN`, `TEAM_TIER_REQUIRED` or `CONNECTOR_TIER_REQUIRED` with the same status, and says so in its own description.
- `404`: `RESOURCE_NOT_FOUND`: an id in the path names nothing the token can see. `TENANT_MISMATCH`: the project sits outside the token's `scope:project:` allow-list, or the token carries no team scope. Both answer 404 rather than 403 so that existence outside the token's scope cannot be inferred.
- `429`: `RATE_LIMITED`: the token has spent its 300 requests a minute or 10,000 an hour; `Retry-After` says when the next one is accepted.

---

[API](https://skmtc.dev/memberpass/apis/subscriby-rest-api.md) · [All operations](https://skmtc.dev/memberpass/apis/subscriby-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/memberpass/apis/subscriby-rest-api/revisions/59c4df91d764?raw)
