In this series of posts I show you how to work with Python 3.x and the Ghost REST API (Admin API and Content API).

Let's assume you have the 2 Ghost sites somedomain1 and somedomain2. On both sites you would like to create, edit, delete etc. posts using Python and the Ghost API.

On both sites go to the Ghost admin page (e.g. https://somedomain1/ghost/), click on Integrations in the left pane and there, under CUSTOM INTEGRATIONS click on +Add custom integration. Give it a name e.g. "Ghost API" and the configuration page opens. There you see a line Content API Key and a line Admin API Key. Both keys will be used in our code.

Create a file ghostAdmin.py and add the code sections below (You will find the complete code for this tutorial in Part 4. If you hover over a code sample you can copy the code by clicking on the tooltip in the upper right corner of the code block).

  1. The imports
import json, requests, jwt
from datetime import datetime as dt
from io import BytesIO

The package jwt is used for authentication (see later createToken()) and BytesIO is used for images (see later loadImage()).

2. Create the class GhostAdmin

Add the methods setSiteData(), createToken() and createHeaders().

class GhostAdmin():
    def __init__(self, siteName):
        self.siteName = siteName
        self.site = None
        self.setSiteData()
        self.token = None
        self.headers = None
        self.createHeaders()

    def setSiteData(self):
        sites = [{'name': 'somedomain1', 'url': 'https://somedomain1.com/', 'AdminAPIKey': '5f...1', 'ContentAPIKey': '0b...9'},\
                 {'name': 'somedomain2', 'url': 'https://somedomain2.com/', 'AdminAPIKey': '5f...', 'ContentAPIKey': '25...e'}]
        self.site = next((site for site in sites if site['name'] == self.siteName), None)

        return None

    def createToken(self):
        key = self.site['AdminAPIKey']
        id, secret = key.split(':')
        iat = int(dt.now().timestamp())
        header = {'alg': 'HS256', 'typ': 'JWT', 'kid': id}
        payload = {'iat': iat, 'exp': iat + (5 * 60), 'aud': '/v3/admin/'}
        self.token = jwt.encode(payload, bytes.fromhex(secret), algorithm='HS256', headers=header)

        return self.token

    def createHeaders(self):
        if self.site != None:
            self.createToken()
            self.headers = {'Authorization': 'Ghost {}'.format(self.token.decode())}

        return self.headers

3. Customize your class

In the method setSiteData() there is a list with all your Ghost sites. Each list item is a dict with the name, url and the AdminAPIKey and ContentAPIKey. Set all dict values to the values of your ghost sites. For the AdminAPIKey and ContentAPIKey see CUSTOM INTEGRATIONS above.

4. Authentication

All API requests to Ghost must be authenticated. For authenticating with the Admin API you must create an access token. This is done in the method createToken(). These are short-lived single-use JSON Web Tokens (JWTs). The lifespan of a token has a maximum of 5 minutes (see above: iat+(5 * 60)). Be aware of token expiration: If you work in the debugger and your app pauses on a breakpoint, the token can expire.

5. HTTP headers

All requests to the Ghost API require HTTP headers: the application name and the access token. The headers are created with the method createHeaders().

6. Endpoints

Now we want to work with the API and use some of its endpoints. First we want to browse through all settings of a site. We add the method getSettings(). This method uses the the endpoint /settings/ of the Content API.

    def getSettings(self):
        settings = {}
        url = self.site['url']+'ghost/api/v3/content/settings/?key='+self.site['ContentAPIKey']
        result = requests.get(url, headers=self.headers)
        if result.ok:
            settings = json.loads(result.content)['settings']

        return settings

In this method you create the request url. It accepts just one parameter, the content api key. It has this form:

https://somedomain1/ghost/api/v3/content/settings/?key='ContentAPIKey'

Given this url and the headers you send a request:

requests.get(url, headers=self.headers)

Now we can already use our class. At the bottom of ghostAdmin.py insert the following code:

    if __name__ == '__main__':
    	ga = GhostAdmin('somedomain1')	# the name of your ghost site
    	settings = ga.getSettings()

The returned value settings is a dict with key, values like title, logo etc.

Proceed to part 2