NAV Navbar

Introduction

Welcome to the Steady API!

You can use our REST-API to fetch data in the scope of your publication. Our API is designed following the JSON API specification.

We implement the OAuth 2.0 authorization framework so that you can implement authentication and authorization for users in your application.

You can view code examples in the dark area to the right, and see example response data for each request.

Our API is only accessible via HTTPS. Enjoy coding!

OAuth 2.0

Create your app

Before you can begin the OAuth process, you must first register a new app with Steady. You can do this in your Steady backend for the project (Your Project Settings -> Integration -> API).

Client ID and Client Secret

Once your application is registered, Steady will issue "client credentials" in the form of a client identifier and a client secret. The Client ID is a publicly exposed string that is used by the Steady API to identify your application, and is also used by you to build authorization URLs that are presented to users in your application. The Client Secret is used to authenticate the identity of your application when your application requests to access a user's account, and must be kept private between your application and the API.

Authorization Grant

The first steps in the OAuth 2.0 flow are about obtaining an authorization grant and access token for a user.

Grant Type: Implicit

We don't offer this flow for clients which cannot use a client secret (e.g. Single Page Apps). Please use Authorization Code grant without client secret for better security.

Grant Type: Authorization Code

The authorization code grant type is the most commonly used because it is optimized for server-side applications, where source code is not publicly exposed, and the client secret can be maintained confidentiality. This is a redirection-based flow, which means that the application must be capable of interacting with the user-agent (i.e. the user's web browser) and receiving API authorization codes that are routed through the user-agent.

Authorization Code Flow

  https://steadyhq.com/oauth/authorize?
    response_type=code&
    client_id=CLIENT_ID&
    redirect_uri=REDIRECT_URI&
    scope=read&
    state=RANDOM_STRING

Create an authorization link, which sends your user to Steady:

https://steadyhq.com/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=read&state=RANDOM_STRING

Parameter Value
response_type code specifies that your application is requesting an authorization code grant
client_id the CLIENT_ID can be found in the Steady Backend
redirect_uri the REDIRECT_URI you have set in the Steady Backend. After authorization Steady will redirect the user-agent to this URI.
scope read specifies the level of access your application is requesting
state a RANDOM_STRING generated by your application, which you'll verify later

Step 2: User authorizes your application at Steady

When the user clicks the link, they must first log in to Steady, to authenticate their identity (unless they are already logged in). When the scope is set to read the user is authorized automatically in order to achieve a smooth user experience. Otherwise the user will be prompted by Steady to authorize or deny your application access to their account. Here is an example authorize application prompt:

Step 3: Your application receives an authorization code

  https://your-website.com/oauth/callback?
    code=AUTHORIZATION_CODE&
    state=RANDOM_STRING

If the user gives the authorization, Steady redirects the user-agent to your application redirect URI, which was specified during the client registration, along with an authorization code. The redirect would look something like this:

https://your-website.com/oauth/callback?code=AUTHORIZATION_CODE&state=RANDOM_STRING

Parameter Value
code authorization code you use to request an access token
state the same state value you passed in before

Step 4: Your application requests the access token

POST /api/v1/oauth/token HTTP/1.1
Accept: application/json
Host: steadyhq.com
{
  "client_id": CLIENT_ID,
  "client_secret": CLIENT_SECRET,
  "grant_type": "authorization_code",
  "code": AUTHORIZATION_CODE,
  "redirect_uri": REDIRECT_URI
}

The application requests an access token from the Steady API, by passing the authorization code along with authentication details, including the client secret, to the API token endpoint.

https://steadyhq.com/api/v1/oauth/token

Parameter Value
client_id the CLIENT_ID can be found in the Steady Backend
client_secret the CLIENT_SECRET can be found in the Steady Backend. Optional.
grant_type authorization_code specifies that this request is within an Authorization Code grant flow
code the AUTHORIZATION_CODE received in Step 3
redirect_uri the REDIRECT_URI you have set in the Steady Backend

Step 5: Your application receives the access token

HTTP/1.1 201 CREATED
Content-Type: application/json; charset=utf-8
{
  "access_token": "V1JvWWVXdHcxajkzK1FBdDRwSS95UT09",
  "refresh_token": "MXpyNWRJRUdaMHg0aW9MM2ZJb1lVQT09"
  "token_type": "bearer",
  "expires_in": 604800,
  "refresh_token_expires_in": 31536000,
  "scope": "read",
  "info": {
    "id": "5e7607b0-1458-41e4-b6bc-e6301c39e7da",
    "first-name": "Jane",
    "last-name": "Doe",
    "email": "jane.doe@example.com"
  }
}

If the authorization request from Step 4 is valid, Steady will send a response containing the access token.

Parameter Value
access_token the access token issued by Steady
refresh_token the refresh token issued by Steady / null
token_type the type of the token issued (bearer)
expires_in time in seconds until the access token expires
refresh_token_expires_in time in seconds until the refresh token expires / null
scope specifies the level of access granted
info the basic user information

Refresh the access token

POST /api/v1/oauth/token HTTP/1.1
Accept: application/json
Host: steadyhq.com
{
  "client_id": CLIENT_ID,
  "client_secret": CLIENT_SECRET,
  "grant_type": "refresh_token",
  "refresh_token": REFRESH_TOKEN,
  "redirect_uri": REDIRECT_URI
}

If a refresh token was issued, it may be used to request new access tokens if the original token has expired. Steady only issues a refresh token if you send the client secret along in Step 4. Make your request to refresh the access token to this endpoint:

https://steadyhq.com/api/v1/oauth/token

Parameter Value
client_id the CLIENT_ID can be found in the Steady Backend
client_secret the CLIENT_SECRET can be found in the Steady Backend.
grant_type refresh_token
refresh_token the REFRESH_TOKEN received in Step 5
redirect_uri the REDIRECT_URI you have set in the Steady Backend
  https://steadyhq.com/your_campaign_page?
    oauth_client_id=CLIENT_ID

If you use the following link to send your users to your Steady campaign page - and they complete the subscription - the user is authorized automatically and the flow will continue with Step 3.

https://steadyhq.com/your_campaign_page?oauth_client_id=CLIENT_ID

Parameter Value
oauth_client_id the CLIENT_ID can be found in the Steady Backend

Authorization

To authorize, add "Authorization" as request header field.

GET /api/v1/users/me HTTP/1.1
Accept: application/vnd.api+json
Authorization: Bearer OAUTH2_ACCESS_TOKEN
Host: steadyhq.com

Make sure to replace OAUTH2_ACCESS_TOKEN with the access token of the user you make the request for.

Steady relies on bearer tokens in the "Authorization" request header field.

Authorization: Bearer OAUTH2_ACCESS_TOKEN

Current user

GET /api/v1/users/me HTTP/1.1
Accept: application/vnd.api+json
Authorization: Bearer OAUTH2_ACCESS_TOKEN
Host: steadyhq.com
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; charset=utf-8
{
  "data": {
    "type": "user",
    "id": "5e7607b0-1458-41e4-b6bc-e6301c39e7da",
    "attributes": {
      "first-name": "Jane",
      "last-name": "Doe",
      "email": "jane.doe@example.com",
      "avatar-url": "https://assets.steadyhq.com/gfx/brand2019/defaults/user/avatar-2.png?auto=format&mask=ellipse&h=200&w=200&crop=faces&fm=png&fit=crop"
    }
  }
}

GET https://steadyhq.com/api/v1/users/me

Returns the current basic user data for the user associated with the access token.

Needed scope of access_token:

read

Attributes

Attribute Description
first-name first name of the user
last-name last name of the user
email email address of the user
avatar-url URL to avatar image of the user, or to a default one

Current subscription

GET /api/v1/subscriptions/me HTTP/1.1
Accept: application/vnd.api+json
Authorization: Bearer OAUTH2_ACCESS_TOKEN
Host: steadyhq.com
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; charset=utf-8
// when the user has a current subscription
{
  "data": {
    "type": "subscription",
    "id": "8ef509c7-b8fe-4a56-a366-fadf030bfc64",
    "attributes": {
      "state": "not_renewing",
      "period": "annual"
      "currency": "EUR",
      "monthly-amount": 1000,
      "monthly-amount-in-cents": 1000,
      "inserted-at": "2017-04-08T10:55:31.000000Z",
      "updated-at": "2017-05-01T10:55:31.000000Z",
      "cancelled-at": "2017-05-01T22:00:14.000000Z",
      "trial-ends-at": "2017-05-08T10:55:31.000000Z",
      "active-from": null,
      "expires-at": "2017-05-18T10:55:31.000000Z",
      "rss-feed-url": "https://steadyhq.com/rss/your-publication?auth=6d58b391-156a-4e88-93ff-3fe773f4394d",
      "is-gift": true
    },
    "relationships": {
      "plan": {
        "data": {
          "type": "plan",
          "id": "00083e16-668b-4bc4-8669-927daa408a1c"
        }
      },
      "subscriber": {
        "data": {
          "type": "user",
          "id": "ffc41bfd-871b-4376-8e02-8729c752b2af"
        }
      },
      "gifter": {
        "data": {
          "type": "user",
          "id": "a00dd134-9e55-4ddb-8f9f-31bb6a06a0b5"
        }
      }
    }
  },
  "included": [
    {
      "type": "plan",
      "id": "b9d7574f-5246-4c94-ade5-1d4e9b169afc",
      "attributes": {
        "state" : "published",
        "name": "Gold plan",
        "currency" : "EUR",
        "monthly-amount" : 2000,
        "monthly-amount-in-cents" : 2000,
        "annual-amount" : 12000,
        "annual-amount-in-cents" : 12000,
        "benefits" : "foo bar baz",
        "ask-for-shiping-address" : false,
        "goal-enabled" : false,
        "subscriptions-goal" : nil,
        "countdown-enabled" : false,
        "countdown-ends-at" : nil,
        "hidden" : false,
        "image-url": "https://assets.steadyhq.com/gfx/steady_logo.svg"
        "inserted-at" : "2018-08-16T09:15:29.803825Z",
        "updated-at" : "2018-08-16T09:15:29.803830Z"
      }
    },
    {
      "type": "user",
      "id": "ffc41bfd-871b-4376-8e02-8729c752b2af",
      "attributes": {
        "email": "alice@example.com",
        "first-name": "Alice",
        "last-name": "Munro",
        "avatar-url": "https://assets.steadyhq.com/gfx/defaults/user/avatar.png?auto=format&crop=faces&fit=crop&fm=png&h=200&mask=ellipse&w=200"
      }
    },
    {
      "type": "user",
      "id": "a00dd134-9e55-4ddb-8f9f-31bb6a06a0b5",
      "attributes": {
        "email": "john@example.com",
        "first-name": "John",
        "last-name": "Doe",
        "avatar-url": "https://assets.steadyhq.com/gfx/defaults/user/avatar.png?auto=format&crop=faces&fit=crop&fm=png&h=200&mask=ellipse&w=200"
      }
    }
  ]
}

// when the user has no current subscription
{
  "data": null
}

GET https://steadyhq.com/api/v1/subscriptions/me

Returns infos about the current subscription for the user associated with the access token. If the user has no subscription, or it has expired, the data attribute of the response is null.

Needed scope of access_token:

read

Subscription attributes

Attribute Description
state guest / in_trial / active / not_renewing
period monthly / annual — the period of the contract of the user
currency EUR / USD / SEK
monthly-amount monthly amount of the associated plan (users don’t pay in states in_trial and guest)
monthly-amount-in-cents DEPRECATED Use monthly-amount instead.
inserted-at datetime of the creation of the subscription
updated-at datetime when the subscription was updated the last time on our system
cancelled-at datetime of the cancellation / null
trial-ends-at datetime when the subscription's trial period will end or has ended / null
active-from datetime when the subscription was paid for the first time/ null
expires-at datetime when the subscription will expire / null
rss-feed-url if you use our podcast features, this is the rss-feed url with authentication for the subscriber
is-gift boolean - if the subscription was a gift. If true, gifter information is included in the payload

Plan attributes

Attribute Description
state draft / published / archived
name name of the plan
currency ISO 4217 currency code of the plan, e.g. EUR / USD / SEK / ...
monthly-amount the amount a user with a monthly contract has to pay per month
monthly-amount-in-cents DEPRECATED Use monthly-amount instead.
annual-amount the amount a user with an annual contract has to pay per year
annual-amount-in-cents DEPRECATED Use annual-amount instead.
benefits the benefits of this plan / null
ask-for-shipping-address boolean if we ask the user for her shipping address after she subscribed
goal-enabled boolean if this plan has a goal of a certain amount of subscriptions
subscriptions-goal integer how many subscription should be reached if goal is enabled / null
subscription-guests-max-count integer / null - maximum number of guest subscriptions associated with a subscription of this plan
countdown-enabled boolean if a countdown for this plan is enabled
countdown-ends-at datetime when the countdown will end if it is enabled / null
hidden boolean if the plan is hidden
image-url plan image url / null
inserted-at datetime of the creation of the plan
updated-at datetime when the plan was updated the last time on our system
giftable boolean - if the plan can be gifted to another user

Steady Widget Integration

The Steady Widget is our javascript plugin that provides features like the Steady Paywall, Steady Checkout, Steady Adblock Detection and more. You can find out more about the Steady Widget in your Steady backend).

Performing OAuth 2.0 authorization while also including the Steady Widget may lead to the login states being out of sync. That's because the Steady Widget implements its own client-side OAuth 2.0 process and will attempt to handle any Authorization Callback (by inspecting the code-query param). This will lead to problems if your implementation already used and as such invalidated the code. If that's the case, you'll need to save the token that you received in step 5 in a cookie called steady-token. This way, the widget will be able to recognize when a user is logged in. Remember to remove this cookie when the user logs out.

REST

The following endpoints are all REST based. You can find your Api-Key in your Steady Backend.

Publication

GET /publication

GET /api/v1/publication HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; charset=utf-8
{
  "data": {
    "type": "publication",
    "id": "0879c0a7-cc51-44fc-ac35-4bec65735d5b",
    "attributes": {
      "title": "Title of your publication",
      "campaign-page-url" : "https://steadyhq.com/your-publication",
      "members-count": 10,
      "paying-members-count": 7,
      "trial-members-count": 2,
      "guest-members-count": 1,
      "monthly-amount": 14223,
      "monthly-amount-in-cents": 14223,
      "editor-name": "Foo Bear",
      "trial-period-activated": true,
      "public": true,
      "js-widget-url": "https://steadyhq.com/widget_loader/0879c0a7-cc51-44fc-ac35-4bec65735d5b",
      "inserted-at" : "2018-08-16T09:15:29.803825Z",
      "updated-at" : "2018-08-16T09:15:29.803830Z"
    }
  }
}

GET https://steadyhq.com/api/v1/publication

Returns infos about the publication associated with the Api-Key.

Attributes

Attribute Description
title the title of the publication
campaign-page-url the url of your steady page
members-count the members count of the publication
paying-members-count the count of paying members of the publication
trial-members-count the count of trial members of the publication
guest-members-count the count of guest members of the publication
monthly-amount the sum of the membership fees, the publication earns in a month
monthly-amount-in-cents DEPRECATED Use monthly-amount instead.
editor-name the name of the publisher as shown on the Steady Page
trial-period-activated boolean if trial memberships are enabled for the publication
public boolean if the publication has been made public
js-widget-url the url of the JS-Steady-Plugin of your publication
inserted-at datetime of the creation of the publication
updated-at datetime when the publication was updated the last time on our system

Plans

GET /plans

GET /api/v1/plans HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; charset=utf-8
{
  "data": [
    {
      "type": "plan",
      "id": "b9d7574f-5246-4c94-ade5-1d4e9b169afc",
      "attributes": {
        "state" : "published",
        "name": "Gold plan",
        "currency" : "EUR",
        "monthly-amount" : 2000,
        "monthly-amount-in-cents" : 2000,
        "annual-amount" : 12000,
        "annual-amount-in-cents" : 12000,
        "benefits" : "foo bar baz",
        "ask-for-shiping-address" : false,
        "goal-enabled" : false,
        "subscriptions-goal" : null,
        "subscription-guests-max-count" : 6,
        "countdown-enabled" : false,
        "countdown-ends-at" : null,
        "hidden" : false,
        "image-url": "https://assets.steadyhq.com/gfx/steady_logo.svg"
        "inserted-at" : "2018-08-16T09:15:29.803825Z",
        "updated-at" : "2018-08-16T09:15:29.803830Z",
        "giftable" : true
      }
    },
    ...
  ]
}

GET https://steadyhq.com/api/v1/plans

Returns an array with all plans of the publication.

Attributes

Attribute Description
state draft / published / archived
name name of the plan
currency ISO 4217 currency code of the plan, e.g. EUR / USD / SEK / ...
monthly-amount the amount a user with a monthly contract has to pay per month
monthly-amount-in-cents DEPRECATED Use monthly-amount instead.
annual-amount the amount a user with an annual contract has to pay per year
annual-amount-in-cents DEPRECATED Use annual-amount instead.
benefits the benefits of this plan / null
ask-for-shipping-address boolean if we ask the user for her shipping address after she subscribed
goal-enabled boolean if this plan has a goal of a certain amount of subscriptions
subscriptions-goal integer how many subscription should be reached if goal is enabled / null
subscription-guests-max-count integer / null - maximum number of guest subscriptions associated with a subscription of this plan
countdown-enabled boolean if a countdown for this plan is enabled
countdown-ends-at datetime when the countdown will end if it is enabled / null
hidden boolean if the plan is hidden
image-url plan image url / null
inserted-at datetime of the creation of the plan
updated-at datetime when the plan was updated the last time on our system
giftable boolean - if the plan can be gifted to another user

Subscriptions

GET /subscriptions

GET /api/v1/subscriptions HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; charset=utf-8
{
  "data": [
    {
      "type": "subscription",
      "id": "8ef509c7-b8fe-4a56-a366-fadf030bfc64",
      "attributes": {
        "state": "not_renewing",
        "period": "annual"
        "currency": "EUR",
        "monthly-amount": 1000,
        "monthly-amount-in-cents": 1000,
        "inserted-at": "2017-04-08T10:55:31.000000Z",
        "updated-at": "2017-05-01T10:55:31.000000Z",
        "cancelled-at": "2017-05-01T22:00:14.000000Z",
        "trial-ends-at": "2017-05-08T10:55:31.000000Z",
        "active-from": null,
        "expires-at": "2017-05-18T10:55:31.000000Z",
        "rss-feed-url": "https://steadyhq.com/rss/your-publication?auth=6d58b391-156a-4e88-93ff-3fe773f4394d",
        "is-gift": true
      },
      "relationships": {
        "plan": {
          "data": {
            "type": "plan",
            "id": "00083e16-668b-4bc4-8669-927daa408a1c"
          }
        },
        "subscriber": {
          "data": {
            "type": "user",
            "id": "ffc41bfd-871b-4376-8e02-8729c752b2af"
          }
        },
        "gifter": {
          "data": {
            "type": "user",
            "id": "a00dd134-9e55-4ddb-8f9f-31bb6a06a0b5"
          }
        }
      }
    },
    ...
  ],
  "included": [
    {
      "type": "plan",
      "id": "b9d7574f-5246-4c94-ade5-1d4e9b169afc",
      "attributes": {
        "state" : "published",
        "name": "Gold plan",
        "currency" : "EUR",
        "monthly-amount" : 2000,
        "monthly-amount-in-cents" : 2000,
        "annual-amount" : 12000,
        "annual-amount-in-cents" : 12000,
        "benefits" : "foo bar baz",
        "ask-for-shiping-address" : false,
        "goal-enabled" : false,
        "subscriptions-goal" : nil,
        "countdown-enabled" : false,
        "countdown-ends-at" : nil,
        "hidden" : false,
        "image-url": "https://assets.steadyhq.com/gfx/steady_logo.svg"
        "inserted-at" : "2018-08-16T09:15:29.803825Z",
        "updated-at" : "2018-08-16T09:15:29.803830Z"
      }
    },
    {
      "type": "user",
      "id": "ffc41bfd-871b-4376-8e02-8729c752b2af",
      "attributes": {
        "email": "alice@example.com",
        "first-name": "Alice",
        "last-name": "Munro",
        "avatar-url": "https://assets.steadyhq.com/gfx/defaults/user/avatar.png?auto=format&crop=faces&fit=crop&fm=png&h=200&mask=ellipse&w=200"
      }
    },
    {
      "type": "user",
      "id": "a00dd134-9e55-4ddb-8f9f-31bb6a06a0b5",
      "attributes": {
        "email": "john@example.com",
        "first-name": "John",
        "last-name": "Doe",
        "avatar-url": "https://assets.steadyhq.com/gfx/defaults/user/avatar.png?auto=format&crop=faces&fit=crop&fm=png&h=200&mask=ellipse&w=200"
      }
    },
    ...
  ]
}

GET https://steadyhq.com/api/v1/subscriptions

Returns an array with all current subscriptions of the publication.

Filters

Subscriptions can be filtered by the subscribers' email addresses. To do this, include a filter[subscriber][email] query parameter. The value of the query parameter should be a (URL encoded) comma-separated list of email addresses. Only subscriptions of subscribers with those email addresses will be returned.

Example:

GET https://steadyhq.com/api/v1/subscriptions?filter[subscriber][email]=alice%40example.com%2Cbob%40example.com

Attributes

Attribute Description
state guest / in_trial / active / not_renewing
period monthly / annual — the period of the contract of the user
currency EUR / USD / SEK
monthly-amount monthly amount of the associated plan (users don’t pay in states in_trial and guest)
monthly-amount-in-cents DEPRECATED Use monthly-amount instead.
inserted-at datetime of the creation of the subscription
updated-at datetime when the subscription was updated the last time on our system
cancelled-at datetime of the cancellation / null
trial-ends-at datetime when the subscription's trial period will end or has ended / null
active-from datetime when the subscription was paid for the first time/ null
expires-at datetime when the subscription will expire / null
rss-feed-url if you use our podcast features, this is the rss-feed url with authentication for the subscriber
is-gift boolean - if the subscription was a gift. If true, gifter information is included in the payload

POST /subscriptions/:subscription_id/cancel

POST /api/v1/subscriptions/8ef509c7-b8fe-4a56-a366-fadf030bfc64/cancel HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; charset=utf-8
{
  "data": {
    "type": "subscription",
    "id": "8ef509c7-b8fe-4a56-a366-fadf030bfc64",
    "attributes": {
      "state": "not_renewing",
      "period": "annual"
      "currency": "EUR",
      "monthly-amount": 1000,
      "monthly-amount-in-cents": 1000,
      "inserted-at": "2017-04-08T10:55:31.000000Z",
      "updated-at": "2017-05-01T10:55:31.000000Z",
      "cancelled-at": "2017-05-01T22:00:14.000000Z",
      "trial-ends-at": "2017-05-08T10:55:31.000000Z",
      "active-from": null,
      "expires-at": "2017-05-18T10:55:31.000000Z",
      "rss-feed-url": "https://steadyhq.com/rss/your-publication?auth=6d58b391-156a-4e88-93ff-3fe773f4394d",
      "is-gift": false
    },
    "relationships": {
      "plan": {
        "data": {
          "type": "plan",
          "id": "00083e16-668b-4bc4-8669-927daa408a1c"
        }
      },
      "subscriber": {
        "data": {
          "type": "user",
          "id": "ffc41bfd-871b-4376-8e02-8729c752b2af"
        }
      }
    },
    "included": [
      {
        "type": "plan",
        "id": "b9d7574f-5246-4c94-ade5-1d4e9b169afc",
        "attributes": {
          "state" : "published",
          "name": "Gold plan",
          "currency" : "EUR",
          "monthly-amount" : 2000,
          "monthly-amount-in-cents" : 2000,
          "annual-amount" : 12000,
          "annual-amount-in-cents" : 12000,
          "benefits" : "foo bar baz",
          "ask-for-shiping-address" : false,
          "goal-enabled" : false,
          "subscriptions-goal" : nil,
          "countdown-enabled" : false,
          "countdown-ends-at" : nil,
          "hidden" : false,
          "image-url": "https://assets.steadyhq.com/gfx/steady_logo.svg"
          "inserted-at" : "2018-08-16T09:15:29.803825Z",
          "updated-at" : "2018-08-16T09:15:29.803830Z"
        }
      },
      {
        "type": "user",
        "id": "ffc41bfd-871b-4376-8e02-8729c752b2af",
        "attributes": {
          "email": "alice@example.com",
          "first-name": "Alice",
          "last-name": "Munro",
          "avatar-url": "https://assets.steadyhq.com/gfx/defaults/user/avatar.png?auto=format&crop=faces&fit=crop&fm=png&h=200&mask=ellipse&w=200"
        }
      }
    ]
  }
}

POST https://steadyhq.com/api/v1/subscriptions/:subscription_id/cancel

Cancels a subscription respecting the end of the current term.

In case the subscription can't be canceled (e.g. because it already is cancelled), a response with status code 422 will be returned.

Attributes

Attribute Description
state not_renewing
period monthly / annual — the period of the contract of the user
currency EUR / USD / SEK
monthly-amount monthly amount of the associated plan (users don't pay in states in_trial and guest)
monthly-amount-in-cents DEPRECATED Use monthly-amount instead.
inserted-at datetime of the creation of the subscription
updated-at datetime when the subscription was updated the last time on our system
cancelled-at datetime of the cancellation / null
trial-ends-at datetime when the subscription's trial period will end or has ended / null
active-from datetime when the subscription was paid for the first time/ null
expires-at datetime when the subscription will expire / null
rss-feed-url if you use our podcast features, this is the rss-feed url with authentication for the subscriber
is-gift boolean - if the subscription was a gift. If true, gifter information is included in the payload

Newsletter subscribers

GET /newsletter_subscribers

GET /api/v1/newsletter_subscribers HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; charset=utf-8
{
    "data": [
        {
            "attributes": {
                "email": "danny@example.com",
                "opted-in-at": "2021-01-29T13:22:12.165517Z"
            },
            "id": "63042c1f-618a-4802-8c73-dd25a3176ed8",
            "type": "newsletter_subscriber"
        }
    ]
}

GET https://steadyhq.com/api/v1/newsletter_subscribers

Returns an array with all current newsletter subscribers of the publication.

Attributes

Attribute Description
email email address of the newsletter subscriber
opted-in-at datetime when the newsletter subscriber clicked the opt-in link in the email

POST /newsletter_subscribers/send_double_opt_in_email

POST /api/v1/newsletter_subscribers/send_double_opt_in_email HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
{
    "email": "alice@example.com"
}
HTTP/1.1 201 OK
Content-Type: application/vnd.api+json; charset=utf-8
{
    "data":
        {
            "email": "alice@example.com"
        }
}
HTTP/1.1 429 Too Many Requests
content-type: application/vnd.api+json; charset=utf-8
{
    "errors": [
        {
            "title": "rate limit exceeded",
            "try_again_in_milliseconds": 928
        }
    ]
}

POST https://steadyhq.com/api/v1/newsletter_subscribers/send_double_opt_in_email

Will send a double opt-in email to the email address provided. Returns the email address, or an error if the email is not valid.

In order to prevent abuse, this endpoint is strongly rate limited. If the response status is 429, you may use the response errors[0].try_again_in_milliseconds parameter to try again later. If you need to import a large list of subscribers, please contact the support team or use the CSV subscriber import feature on your Steady backend.

Attributes

Attribute Description
email email address of the prospective newsletter subscriber

Audio posts

Creating a post

POST https://steadyhq.com/api/v1/posts/audio_posts

A post can be created in an already-published state by setting published_at or you can schedule a publication date in the future by using publish_at.

POST /api/v1/posts/audio_posts HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
{
    "audio_url": "https://example.com/episode3.mp3",
    "title": "My title",
    "description": "Episode description",
    "content": "<p>Some content</p>",
    "teaser_image": "https://some-url.png",
    "restrict_to_plan_ids": ["9f00e91b-6700-452a-a2b8-37e7964fa442"],
    "publish_at": "2070-01-01T00:00:00Z"
}
HTTP/1.1 201 Created
content-type: application/vnd.api+json; charset=utf-8
{
   "data":{
      "attributes":{
         "description":"Episode description",
         "title":"My title",
         "content":"<p>Some content</p>",
         "audio_url":"https://example.com/episode3.mp3",
         "restricted":true,
         "teaser-image":"https://some-url.png",
         "publish-at":"2070-01-01T00:00:00.000000Z",
         "published-at":null,
         "distribute-on-steady-page":true,
         "distribute-as-email":true
      },
      "id":"4049854a-6f01-435a-b582-3320dce7f74c",
      "type":"audio-post",
      "relationships":{
         "publication":{
            "data":{
               "id":"58bbd664-dbb3-47bd-a164-e36aa0bb2850",
               "type":"publication"
            }
         },
         "plans_with_access":{
            "data":[
               {
                  "id":"9f00e91b-6700-452a-a2b8-37e7964fa442",
                  "type":"plan"
               }
            ]
         }
      }
   }
}

Attributes

Attribute Description
audio_url (required) A URL ending in either .mp3 or .m4a.
title (required) The title of the post. Max. 280 characters.
description (required) The description of the post. Max. 5000 characters.
content (optional) The content of the post. Can contain markup but it will be sanitized.
teaser_image (optional) An image URL. It will be used when displaying the post on Steady.
publish_at (optional) A datetime in the ISO8601 format indicating when to publish the post (has to be in the future). Mutually exclusive with published_at.
published_at (optional) A datetime in the ISO8601 format indicating when the post was published. If missing, it will default to now(). Mutually exclusive with publish_at.
restrict_to_plan_ids (optional) An array of plan ids with access to this post. The post will be public if the value is ommited, or if the values [] or null are provided. For getting a list of your plans, see the section below.
distribute_on_steady_page (optional) A boolean indicating whether the post should be displayed on your Steady page. Defaults to true.
distribute_as_email (optional) A boolean indicating whether the post should be sent as email. If restrict_to_plan_ids is specified, only members of those plans will receive the email. Emails are sent only once, when the post is published. Defaults to true.

Updating a post

PUT https://steadyhq.com/api/v1/posts/audio_posts/{post_id}

Updates a post created with the API.

PUT /api/v1/posts/audio_posts/4049854a-6f01-435a-b582-3320dce7f74c HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
{
    "audio_url": "https://example-updated.com/episode3.mp3",
    "title": "My updated title",
    "description": "Episode description updated",
    "content": "<p>Some updated content</p>",
    "teaser_image": "https://some-updated-url.png",
    "restrict_to_plan_ids": null,
    "distribute_as_email": false
}
HTTP/1.1 200 OK
content-type: application/vnd.api+json; charset=utf-8
{
   "data":{
      "attributes":{
         "description":"Episode description updated",
         "title":"My updated title",
         "content":"<p>Some updated content</p>",
         "audio_url":"https://example-updated.com/episode3.mp3",
         "restricted":false,
         "teaser-image":"https://some-updated-url.png",
         "publish-at":"2070-01-01T00:00:00.000000Z",
         "published-at":null,
         "distribute-on-steady-page":true,
         "distribute-as-email":false
      },
      "id":"4049854a-6f01-435a-b582-3320dce7f74c",
      "type":"audio-post",
      "relationships":{
         "publication":{
            "data":{
               "id":"58bbd664-dbb3-47bd-a164-e36aa0bb2850",
               "type":"publication"
            }
         },
         "plans_with_access":{
            "data":[
               {
                  "id":"9f00e91b-6700-452a-a2b8-37e7964fa442",
                  "type":"plan"
               },
               {
                  "id":"3bd996cf-9f09-4642-b4bd-84c3b46e0301",
                  "type":"plan"
               }
            ]
         }
      }
   }
}

Attributes

Attribute Description
audio_url A URL ending in either .mp3 or .m4a.
title The title of the post. Max. 280 characters.
description The description of the post. Max. 5000 characters.
content The content of the post. Can contain markup but it will be sanitized.
teaser_image An image URL. It will be used when displaying the post on Steady.
publish_at A datetime in the ISO8601 format indicating when to publish the post (has to be in the future). Can only be especified if the post is not already published.
restrict_to_plan_ids An array of plan ids with access to this post. The post will be public if the value is ommited, or if the values [] or null are provided. For getting a list of your plans, see the section below.
distribute_on_steady_page A boolean indicating whether the post should be displayed on your Steady page. Defaults to true.
distribute_as_email A boolean indicating whether the post should be sent as email. If restrict_to_plan_ids is specified, only members of those plans will receive the email. Emails are sent only once, when the post is published. Defaults to true.

Deleting a post

DELETE https://steadyhq.com/api/v1/posts/audio_posts/{post_id}

Deletes a post created with the API.

DELETE /api/v1/posts/audio_posts/4049854a-6f01-435a-b582-3320dce7f74c HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
HTTP/1.1 200 OK
content-type: application/vnd.api+json; charset=utf-8
{
   "data":{
      "id":"4049854a-6f01-435a-b582-3320dce7f74c"
   }
}

Listing plans with access

GET https://steadyhq.com/api/v1/posts/plans_for_access_control

Returns a list of all plans of a publication, excluding draft plans and archived plans without members.

GET /api/v1/posts/plans_for_access_control HTTP/1.1
Accept: application/vnd.api+json
X-Api-Key: YOUR_API_KEY
Host: steadyhq.com
HTTP/1.1 200 OK
content-type: application/vnd.api+json; charset=utf-8
{
   "data":[
      {
         "attributes":{
            "hidden":false,
            "name":"Standard Membership",
            "state":"published",
            "currency":"EUR",
            "benefits":"• Support my work\r\n• Join my community",
            "giftable":true,
            "monthly-amount-in-cents":500,
            "monthly-amount":500,
            "inserted-at":"2024-08-08T10:36:35.377137Z",
            "updated-at":"2024-08-26T11:12:33.819556Z",
            "annual-amount-in-cents":6000,
            "annual-amount":6000,
            "image-url":null,
            "goal-enabled":false,
            "subscriptions-goal":null,
            "countdown-enabled":false,
            "countdown-ends-at":null,
            "ask-for-shiping-address":false,
            "subscription-guests-max-count":null
         },
         "id":"9f00e91b-6700-452a-a2b8-37e7964fa442",
         "type":"plan"
      },
      {
         "attributes":{
            "hidden":false,
            "name":"Big Membership",
            "state":"published",
            "currency":"EUR",
            "benefits":null,
            "giftable":true,
            "monthly-amount-in-cents":1000,
            "monthly-amount":1000,
            "inserted-at":"2024-08-14T12:56:44.279130Z",
            "updated-at":"2024-08-14T12:56:50.374319Z",
            "annual-amount-in-cents":10800,
            "annual-amount":10800,
            "image-url":null,
            "goal-enabled":false,
            "subscriptions-goal":null,
            "countdown-enabled":false,
            "countdown-ends-at":null,
            "ask-for-shiping-address":false,
            "subscription-guests-max-count":null
         },
         "id":"3bd996cf-9f09-4642-b4bd-84c3b46e0301",
         "type":"plan"
      }
   ]
}