# The client object

## Storing and restoring client state

The `FinTS3Client` object keeps some internal state that’s beneficial to keep across invocations. This includes

> - A system identifier that uniquely identifies this particular FinTS endpoint

> - The Bank Parameter Data (BPD) with information about the bank and its advertised capabilities

> - The User Parameter Data (UPD) with information about the user account and allowed actions

class fints.client.FinTS3Client(bank_identifier, user_id, customer_id=None, from_data: bytes = None, product_id=None, product_version='4.0.0', mode=FinTSClientMode.INTERACTIVE)
  deconstruct(including_private: bool = False) → bytes

    Return state of this FinTSClient instance as an opaque datablob. You should not use this object after calling this method.

    Information about the connection is implicitly retrieved from the bank and cached in the FinTSClient. This includes: system identifier, bank parameter data, user parameter data. It’s not strictly required to retain this information across sessions, but beneficial. If possible, an API user SHOULD use this method to serialize the client instance before destroying it, and provide the serialized data next time an instance is constructed.

    Parameter including_private should be set to True, if the storage is sufficiently secure (with regards to confidentiality) to include private data, specifically, account numbers and names. Most often this is the case.

    Note: No connection information is stored in the datablob, neither is the PIN.

  set_data(blob: bytes)

    Restore a datablob created with deconstruct().

    You should only call this method once, and only immediately after constructing the object and before calling any other method or functionality (e.g. __enter__()). For convenience, you can pass the from_data parameter to __init__().

Using the `deconstruct()`/`set_data()` facility is purely optional for reading operations, but may speed up the process because the BPD/UPD can be cached and need not be transmitted again.

It may be required to use the facility for transaction operations if both parts of a two-step transaction cannot be completed with the same `FinTS3Client` object.

The `deconstruct()` parameter include_private (defaults to False) enables including the User Parameter Data in the datablob. Set this to True if you can sufficiently ensure the privacy of the returned datablob (mostly: user name and account numbers).

If your system manages multiple users/identity contexts, you SHOULD keep distinct datablobs per user or context.

You SHOULD NOT call any other methods on the `FinTS3Client` object after calling `deconstruct()`.

## Keeping the dialog open

All FinTS operations happen in the context of a so-called “dialog”. The simple reading operations of this library will automatically open and close the dialog when necessary, but each opening and each closing takes one FinTS roundtrip.

For the case where multiple operations are to be performed one after the other you can indicate to the library that you want to open a standing dialog and keep it open explicitly by entering the `FinTS3Client` as a context handler.

This can, and should be, complemented with the client state facility as follows:

    datablob = ... # get from backend storage, or set to None
    client = FinTS3PinTanClient(..., from_data=datablob)

    with client:
        accounts = client.get_sepa_accounts()
        balance = client.get_balance(accounts[0])
        transactions = client.get_transactions(accounts[0])

    datablob = client.deconstruct()
    # Store datablob to backend storage

For transactions involving TANs it may be required by the bank to issue both steps for one transaction within the same dialog. In this case it’s mandatory to use a standing dialog, because otherwise each step would be issued in its own, implicit, dialog.

## Storing and restoring dialog state

class fints.client.FinTS3Client(bank_identifier, user_id, customer_id=None, from_data: bytes = None, product_id=None, product_version='4.0.0', mode=FinTSClientMode.INTERACTIVE)
  pause_dialog()

    Pause a standing dialog and return the saved dialog state.

    Sometimes, for example in a web app, it’s not possible to keep a context open during user input. In some cases, though, it’s required to send a response within the same dialog that issued the original task (f.e. TAN with TANTimeDialogAssociation.NOT_ALLOWED). This method freezes the current standing dialog (started with FinTS3Client.__enter__()) and returns the frozen state.

    Commands MUST NOT be issued in the dialog after calling this method.

    MUST be used in conjunction with deconstruct()/set_data().

    Caller SHOULD ensure that the dialog is resumed (and properly ended) within a reasonable amount of time.

    Example:

        client = FinTS3PinTanClient(..., from_data=None)
        with client:
            challenge = client.sepa_transfer(...)

            dialog_data = client.pause_dialog()

            # dialog is now frozen, no new commands may be issued
            # exiting the context does not end the dialog

        client_data = client.deconstruct()

        # Store dialog_data and client_data out-of-band somewhere
        # ... Some time passes ...
        # Later, possibly in a different process, restore the state

        client = FinTS3PinTanClient(..., from_data=client_data)
        with client.resume_dialog(dialog_data):
            client.send_tan(...)

            # Exiting the context here ends the dialog, unless frozen with pause_dialog() again.

  resume_dialog(dialog_data)