Skip to content

client

pymonzo API client code.

MonzoAPI

Monzo public API client.

To use it, you need to create a new OAuth client in Monzo Developer Portal. The Redirect URLs should be set to http://localhost:6600/pymonzo and Confidentiality should be set to Confidential if you'd like to automatically refresh the access token when it expires.

You can now use Client ID and Client secret in pymonzo.MonzoAPI.authorize to finish the OAuth 2 'Authorization Code Flow' and get the API access token (which is by default saved to disk and refreshed when expired).

Note

Monzo API docs: https://docs.monzo.com/

Source code in pymonzo/client.py
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
class MonzoAPI:
    """Monzo public API client.

    To use it, you need to create a new OAuth client in [Monzo Developer Portal].
    The `Redirect URLs` should be set to `http://localhost:6600/pymonzo` and
    `Confidentiality` should be set to `Confidential` if you'd like to automatically
    refresh the access token when it expires.

    You can now use `Client ID` and `Client secret` in [`pymonzo.MonzoAPI.authorize`][]
    to finish the OAuth 2 'Authorization Code Flow' and get the API access token
    (which is by default saved to disk and refreshed when expired).

    [Monzo Developer Portal]: https://developers.monzo.com/

    Note:
        Monzo API docs: https://docs.monzo.com/
    """

    api_url = "https://api.monzo.com"
    authorization_endpoint = "https://auth.monzo.com/"
    token_endpoint = "https://api.monzo.com/oauth2/token"  # noqa
    settings_path = Path.home() / ".pymonzo"

    def __init__(self, access_token: Optional[str] = None) -> None:
        """Initialize Monzo API client and mount all resources.

        It expects [`pymonzo.MonzoAPI.authorize`][] to be called beforehand, so
        it can load the local settings file containing the API access token. You
        can also explicitly pass the `access_token`, but it won't be able to
        automatically refresh it once it expires.

        Arguments:
            access_token: OAuth access token. You can obtain it (and by default, save
                it to disk, so it can refresh automatically) by running
                [`pymonzo.MonzoAPI.authorize`][]. Alternatively, you can get a
                temporary access token from the [Monzo Developer Portal].

                [Monzo Developer Portal]: https://developers.monzo.com/

        Raises:
            NoSettingsFile: When the access token wasn't passed explicitly and the
                settings file couldn't be loaded.

        """
        if access_token:
            self._settings = PyMonzoSettings(
                token={"access_token": access_token},
            )
        else:
            try:
                self._settings = PyMonzoSettings.load_from_disk(self.settings_path)
            except (FileNotFoundError, JSONDecodeError) as e:
                raise NoSettingsFile(
                    "No settings file found. You need to either run "
                    "`MonzoAPI.authorize(client_id, client_secret)` "
                    "to get the authorization token (and save it to disk), "
                    "or explicitly pass the `access_token`."
                ) from e

        self.session = OAuth2Client(
            client_id=self._settings.client_id,
            client_secret=self._settings.client_secret,
            token=self._settings.token,
            authorization_endpoint=self.authorization_endpoint,
            token_endpoint=self.token_endpoint,
            token_endpoint_auth_method="client_secret_post",  # noqa
            update_token=self._update_token,
            base_url=self.api_url,
        )

        # This is a shortcut to the underlying method
        self.whoami = WhoAmIResource(client=self).whoami
        """
        Mounted Monzo `whoami` endpoint. For more information see
        [`pymonzo.whoami.WhoAmIResource.whoami`][].
        """

        self.accounts = AccountsResource(client=self)
        """
        Mounted Monzo `accounts` resource. For more information see
        [`pymonzo.accounts.AccountsResource`][].
        """

        self.attachments = AttachmentsResource(client=self)
        """
        Mounted Monzo `attachments` resource. For more information see
        [`pymonzo.attachments.AttachmentsResource`][].
        """

        self.balance = BalanceResource(client=self)
        """
        Mounted Monzo `balance` resource. For more information see
        [`pymonzo.balance.BalanceResource`][].
        """

        self.feed = FeedResource(client=self)
        """
        Mounted Monzo `feed` resource. For more information see
        [`pymonzo.feed.FeedResource`][].
        """

        self.pots = PotsResource(client=self)
        """
        Mounted Monzo `pots` resource. For more information see
        [`pymonzo.pots.PotsResource`][].
        """

        self.transactions = TransactionsResource(client=self)
        """
        Mounted Monzo `transactions` resource. For more information see
        [`pymonzo.transactions.TransactionsResource`][].
        """

        self.webhooks = WebhooksResource(client=self)
        """
        Mounted Monzo `webhooks` resource. For more information see
        [`pymonzo.webhooks.WebhooksResource`][].
        """

    @classmethod
    def authorize(
        cls,
        client_id: str,
        client_secret: str,
        *,
        save_to_disk: bool = True,
        redirect_uri: str = "http://localhost:6600/pymonzo",
    ) -> dict:
        """Use OAuth 2 'Authorization Code Flow' to get Monzo API access token.

        By default, it also saves the token to disk, so it can be loaded during
        [`pymonzo.MonzoAPI`][] initialization.

        Note:
            Monzo API docs: https://docs.monzo.com/#authentication

        Arguments:
            client_id: OAuth client ID.
            client_secret: OAuth client secret.
            save_to_disk: Whether to save the token to disk.
            redirect_uri: Redirect URI specified in OAuth client.

        Returns:
            OAuth token.
        """
        client = OAuth2Client(
            client_id=client_id,
            client_secret=client_secret,
            redirect_uri=redirect_uri,
            token_endpoint_auth_method="client_secret_post",  # noqa
        )
        url, state = client.create_authorization_url(cls.authorization_endpoint)

        print(f"Please visit this URL to authorize: {url}")  # noqa
        webbrowser.open(url)

        # Start a webserver and wait for the callback
        parsed_url = urlparse(redirect_uri)
        assert parsed_url.hostname is not None
        assert parsed_url.port is not None
        authorization_response = get_authorization_response_url(
            host=parsed_url.hostname,
            port=parsed_url.port,
        )

        try:
            token = client.fetch_token(
                url=cls.token_endpoint,
                authorization_response=authorization_response,
            )
        except (OAuthError, JSONDecodeError) as e:
            raise MonzoAPIError("Error while fetching API access token") from e

        # Save settings to disk
        if save_to_disk:
            settings = PyMonzoSettings(
                client_id=client_id,
                client_secret=client_secret,
                token=token,
            )
            settings.save_to_disk(cls.settings_path)

        return token

    def _update_token(self, token: dict, **kwargs: Any) -> None:
        """Update settings with refreshed access token and save it to disk.

        Arguments:
            token: OAuth access token.
            **kwargs: Extra kwargs.
        """
        self._settings.token = token
        if self.settings_path.exists():
            self._settings.save_to_disk(self.settings_path)

accounts = AccountsResource(client=self) instance-attribute

Mounted Monzo accounts resource. For more information see pymonzo.accounts.AccountsResource.

attachments = AttachmentsResource(client=self) instance-attribute

Mounted Monzo attachments resource. For more information see pymonzo.attachments.AttachmentsResource.

balance = BalanceResource(client=self) instance-attribute

Mounted Monzo balance resource. For more information see pymonzo.balance.BalanceResource.

feed = FeedResource(client=self) instance-attribute

Mounted Monzo feed resource. For more information see pymonzo.feed.FeedResource.

pots = PotsResource(client=self) instance-attribute

Mounted Monzo pots resource. For more information see pymonzo.pots.PotsResource.

transactions = TransactionsResource(client=self) instance-attribute

Mounted Monzo transactions resource. For more information see pymonzo.transactions.TransactionsResource.

webhooks = WebhooksResource(client=self) instance-attribute

Mounted Monzo webhooks resource. For more information see pymonzo.webhooks.WebhooksResource.

whoami = WhoAmIResource(client=self).whoami instance-attribute

Mounted Monzo whoami endpoint. For more information see pymonzo.whoami.WhoAmIResource.whoami.

__init__(access_token=None)

Initialize Monzo API client and mount all resources.

It expects pymonzo.MonzoAPI.authorize to be called beforehand, so it can load the local settings file containing the API access token. You can also explicitly pass the access_token, but it won't be able to automatically refresh it once it expires.

Parameters:

Name Type Description Default
access_token Optional[str]

OAuth access token. You can obtain it (and by default, save it to disk, so it can refresh automatically) by running pymonzo.MonzoAPI.authorize. Alternatively, you can get a temporary access token from the Monzo Developer Portal.

None

Raises:

Type Description
NoSettingsFile

When the access token wasn't passed explicitly and the settings file couldn't be loaded.

Source code in pymonzo/client.py
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def __init__(self, access_token: Optional[str] = None) -> None:
    """Initialize Monzo API client and mount all resources.

    It expects [`pymonzo.MonzoAPI.authorize`][] to be called beforehand, so
    it can load the local settings file containing the API access token. You
    can also explicitly pass the `access_token`, but it won't be able to
    automatically refresh it once it expires.

    Arguments:
        access_token: OAuth access token. You can obtain it (and by default, save
            it to disk, so it can refresh automatically) by running
            [`pymonzo.MonzoAPI.authorize`][]. Alternatively, you can get a
            temporary access token from the [Monzo Developer Portal].

            [Monzo Developer Portal]: https://developers.monzo.com/

    Raises:
        NoSettingsFile: When the access token wasn't passed explicitly and the
            settings file couldn't be loaded.

    """
    if access_token:
        self._settings = PyMonzoSettings(
            token={"access_token": access_token},
        )
    else:
        try:
            self._settings = PyMonzoSettings.load_from_disk(self.settings_path)
        except (FileNotFoundError, JSONDecodeError) as e:
            raise NoSettingsFile(
                "No settings file found. You need to either run "
                "`MonzoAPI.authorize(client_id, client_secret)` "
                "to get the authorization token (and save it to disk), "
                "or explicitly pass the `access_token`."
            ) from e

    self.session = OAuth2Client(
        client_id=self._settings.client_id,
        client_secret=self._settings.client_secret,
        token=self._settings.token,
        authorization_endpoint=self.authorization_endpoint,
        token_endpoint=self.token_endpoint,
        token_endpoint_auth_method="client_secret_post",  # noqa
        update_token=self._update_token,
        base_url=self.api_url,
    )

    # This is a shortcut to the underlying method
    self.whoami = WhoAmIResource(client=self).whoami
    """
    Mounted Monzo `whoami` endpoint. For more information see
    [`pymonzo.whoami.WhoAmIResource.whoami`][].
    """

    self.accounts = AccountsResource(client=self)
    """
    Mounted Monzo `accounts` resource. For more information see
    [`pymonzo.accounts.AccountsResource`][].
    """

    self.attachments = AttachmentsResource(client=self)
    """
    Mounted Monzo `attachments` resource. For more information see
    [`pymonzo.attachments.AttachmentsResource`][].
    """

    self.balance = BalanceResource(client=self)
    """
    Mounted Monzo `balance` resource. For more information see
    [`pymonzo.balance.BalanceResource`][].
    """

    self.feed = FeedResource(client=self)
    """
    Mounted Monzo `feed` resource. For more information see
    [`pymonzo.feed.FeedResource`][].
    """

    self.pots = PotsResource(client=self)
    """
    Mounted Monzo `pots` resource. For more information see
    [`pymonzo.pots.PotsResource`][].
    """

    self.transactions = TransactionsResource(client=self)
    """
    Mounted Monzo `transactions` resource. For more information see
    [`pymonzo.transactions.TransactionsResource`][].
    """

    self.webhooks = WebhooksResource(client=self)
    """
    Mounted Monzo `webhooks` resource. For more information see
    [`pymonzo.webhooks.WebhooksResource`][].
    """

authorize(client_id, client_secret, *, save_to_disk=True, redirect_uri='http://localhost:6600/pymonzo') classmethod

Use OAuth 2 'Authorization Code Flow' to get Monzo API access token.

By default, it also saves the token to disk, so it can be loaded during pymonzo.MonzoAPI initialization.

Note

Monzo API docs: https://docs.monzo.com/#authentication

Parameters:

Name Type Description Default
client_id str

OAuth client ID.

required
client_secret str

OAuth client secret.

required
save_to_disk bool

Whether to save the token to disk.

True
redirect_uri str

Redirect URI specified in OAuth client.

'http://localhost:6600/pymonzo'

Returns:

Type Description
dict

OAuth token.

Source code in pymonzo/client.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
@classmethod
def authorize(
    cls,
    client_id: str,
    client_secret: str,
    *,
    save_to_disk: bool = True,
    redirect_uri: str = "http://localhost:6600/pymonzo",
) -> dict:
    """Use OAuth 2 'Authorization Code Flow' to get Monzo API access token.

    By default, it also saves the token to disk, so it can be loaded during
    [`pymonzo.MonzoAPI`][] initialization.

    Note:
        Monzo API docs: https://docs.monzo.com/#authentication

    Arguments:
        client_id: OAuth client ID.
        client_secret: OAuth client secret.
        save_to_disk: Whether to save the token to disk.
        redirect_uri: Redirect URI specified in OAuth client.

    Returns:
        OAuth token.
    """
    client = OAuth2Client(
        client_id=client_id,
        client_secret=client_secret,
        redirect_uri=redirect_uri,
        token_endpoint_auth_method="client_secret_post",  # noqa
    )
    url, state = client.create_authorization_url(cls.authorization_endpoint)

    print(f"Please visit this URL to authorize: {url}")  # noqa
    webbrowser.open(url)

    # Start a webserver and wait for the callback
    parsed_url = urlparse(redirect_uri)
    assert parsed_url.hostname is not None
    assert parsed_url.port is not None
    authorization_response = get_authorization_response_url(
        host=parsed_url.hostname,
        port=parsed_url.port,
    )

    try:
        token = client.fetch_token(
            url=cls.token_endpoint,
            authorization_response=authorization_response,
        )
    except (OAuthError, JSONDecodeError) as e:
        raise MonzoAPIError("Error while fetching API access token") from e

    # Save settings to disk
    if save_to_disk:
        settings = PyMonzoSettings(
            client_id=client_id,
            client_secret=client_secret,
            token=token,
        )
        settings.save_to_disk(cls.settings_path)

    return token