Skip to main content

Fintoc meets Python 🐍

You have just found the Python-flavored client of Fintoc.

PyPI - Version Tests Coverage Linters

Table of Contents

Installation

Install using pip!

pip install fintoc

Note: This SDK requires Python 3.6+.

Usage

The idea behind this SDK is to stick to the API design as much as possible, so that it feels ridiculously natural to use even while only reading the raw API documentation.

Quickstart

To be able to use this SDK, you first need to get your secret API Key from the Fintoc Dashboard. Once you have your API key, all you need to do is initialize a Fintoc object with it and you're ready to start enjoying Fintoc!

from fintoc import Fintoc

client = Fintoc("your_api_key")

# list all succeeded payment intents since the beginning of 2025
payment_intents = client.payment_intents.list(since="2025-01-01", status="succeeded")
for pi in payment_intents:
    print(pi.created_at, pi.amount, pi.customer_email)

# Get a specific payment intent
payment_intent = client.payment_intents.get("pi_12345235412")
print(payment_intent.customer_email)

Calling endpoints

The SDK provides direct access to Fintoc API resources following the API structure. Simply use the resource name and follow it by the appropriate action you want.

Notice that not every resource has all of the methods, as they correspond to the API capabilities.

list

You can use the list method to list all the instances of the resource:

webhook_endpoints = client.webhook_endpoints.list()

The list method returns a generator with all the instances of the resource. This method can also receive the arguments that the API receives for that specific resource. For example, the PaymentIntent resource can be filtered using since and until, so if you wanted to get a range of payment intents, all you need to do is to pass the parameters to the method:

payment_intents = client.payment_intents.list(since="2025-01-01", until="2025-02-01")

You can also pass the lazy=False parameter to the method to force the SDK to return a list of all the instances of the resource instead of the generator. Beware: this could take very long, depending on the amount of instances that exist of said resource:

payment_intents = client.payment_intents.list(since="2025-01-01", until="2025-02-01", lazy=False)

isinstance(payment_intents, list)  # True

get

You can use the get method to get a specific instance of the resource:

payment_intent = client.payment_intents.get("pi_8anqVLlBC8ROodem")

create

You can use the create method to create an instance of the resource:

webhook_endpoint = client.webhook_endpoints.create(
    url="https://webhook.site/58gfb429-c33c-20c7-584b-d5ew3y3202a0",
    enabled_events=["link.credentials_changed"],
    description="Fantasting webhook endpoint",
)

The create method of the managers creates and returns a new instance of the resource. The attributes used for creating the object are passed as kwargs, and correspond to the parameters specified by the API documentation for the creation of said resource.

update

You can use the update method to update an instance of the resource:

webhook_endpoint = client.webhook_endpoints.update(
    "we_8anqVLlBC8ROodem",
    enabled_events=["account.refresh_intent.succeeded"],
    disabled=True,
)

The update method updates and returns an existing instance of the resource using its identifier to find it. The first parameter of the method corresponds to the identifier being used to find the existing instance of the resource. The attributes to be modified are passed as kwargs, and correspond to the parameters specified by the API documentation for the update action of said resource.

delete

You can use the delete method to delete an instance of the resource:

deleted_identifier = client.webhook_endpoints.delete("we_8anqVLlBC8ROodem")

The delete method deletes an existing instance of the resource using its identifier to find it and returns the identifier.

v2 Endpoints

To call v2 API endpoints, like the Transfers API, you need to prepend the resource name with the v2 namespace, the same as the API does it:

transfer = client.v2.transfers.create(
    amount=49523,
    currency="mxn",
    account_id="acc_123545",
    counterparty={"account_number": "014180655091438298"},
    metadata={"factura": "14814"},
)

Nested actions or resources

To call nested actions just call the method as it appears in the API. For example to simulate receiving a transfer for the Transfers product you can do:

transfer = client.v2.simulate.receive_transfer(
    amount=9912400,
    currency="mxn",
    account_number_id="acno_2vF18OHZdXXxPJTLJ5qghpo1pdU",
)

Entity onboardings

Entity onboardings are nested under an entity, so every call takes the entity_id of the entity that owns them.

onboardings = client.v2.entities.onboardings.list(entity_id="ent_8anBwgZktbZH6ydyHa6Tm0eM")
onboarding = client.v2.entities.onboardings.get(
    "onbprc_0ujsswThIGTUYm2K8FjOOfXtY1K", entity_id="ent_8anBwgZktbZH6ydyHa6Tm0eM"
)

To create one, pass the type of onboarding to run (account_holder or settlement_recipient) and the onboarding data:

onboarding = client.v2.entities.onboardings.create(
    entity_id="ent_8anBwgZktbZH6ydyHa6Tm0eM",
    type="account_holder",
    data={
        "company_information": {
            "incorporation_date": "2020-01-15",
            "business_activity": "Servicios financieros",
            "fiscal_address": "Av. Reforma 123, CDMX",
            "business_address": "Av. Insurgentes 456, CDMX",
            "settlement_account": "646180357600000013",
            "phone": "+521111111111",
        },
        "legal_representatives": [
            {
                "first_name": "Ada",
                "last_name": "Lovelace",
                "email": "ada@example.com",
                "nationality": "mx",
                "identification_number": "AAAA010101HDFAAA01",
                "position": "Director General",
            }
        ],
        "transactional_profile": {
            "resource_origins": ["trusts", "investments"],
            "monthly_amount_range": "1_500000",
            "monthly_operations_range": "1_15000",
        },
        "shareholders": [
            {
                "type": "natural_person",
                "name": "Ada",
                "last_name": "Lovelace",
                "nationality": "mx",
                "percentage": 100,
                "holder_id": "AAAA010101AAA",
            }
        ],
    },
)

Documents are uploaded one slot at a time. The file can be a path or a binary file-like object:

entity_id = "ent_8anBwgZktbZH6ydyHa6Tm0eM"
onboarding_id = "onbprc_0ujsswThIGTUYm2K8FjOOfXtY1K"

client.v2.entities.onboardings.upload_document(
    onboarding_id, "tax_registration_certificate", "csf.pdf", entity_id=entity_id
)
client.v2.entities.onboardings.upload_shareholder_document(
    onboarding_id, "onbsh_0ujsswThIGTUYm2K8FjOOfXtY1K", "id.png", entity_id=entity_id
)
client.v2.entities.onboardings.upload_legal_representative_document(
    onboarding_id,
    "onblr_0ujsswThIGTUYm2K8FjOOfXtY1K",
    "identification",
    "id.png",
    entity_id=entity_id,
)

Once every required field and document is complete, submittable turns True and the onboarding can be sent for review:

onboarding = client.v2.entities.onboardings.submit(onboarding_id, entity_id=entity_id)

Transfer batches

Transfer batches let you send several transfers in a single request. Creating one requires the JWS Signature:

transfer_batch = client.v2.transfer_batches.create(
    description="Payroll October",
    currency="mxn",
    transfers=[
        {
            "account_id": "acc_123545",
            "amount": 49523,
            "counterparty": {"account_number": "014180655091438298"},
            "comment": "Salary",
            "metadata": {"employee_id": "123"},
        },
    ],
)

To list them, filtering by creation date:

transfer_batches = client.v2.transfer_batches.list(
    since="2026-01-01T00:00:00Z", until="2026-02-01T00:00:00Z"
)

Webhook Signature Validation

To ensure the authenticity of incoming webhooks from Fintoc, you should always validate the signature. The SDK provides a WebhookSignature class to verify the Fintoc-Signature header

WebhookSignature.verify_header(
    payload=request.get_data().decode('utf-8'),
    header=request.headers.get('Fintoc-Signature'),
    secret='your_webhook_secret'
)

The verify_header method takes the following parameters:

  • payload: The raw request body as a string
  • header: The Fintoc-Signature header value
  • secret: Your webhook secret key (found in your Fintoc dashboard)
  • tolerance: (Optional) Number of seconds to tolerate when checking timestamp (default: 300)

If the signature is invalid or the timestamp is outside the tolerance window, a WebhookSignatureError will be raised with a descriptive message.

For a complete example of handling webhooks, see examples/webhook.py.

Idempotency Keys

You can provide an Idempotency Key using the idempotency_key argument. For example:

transfer = client.v2.transfers.create(
    idempotency_key="12345678910"
    amount=49523,
    currency="mxn",
    account_id="acc_123545",
    counterparty={"account_number": "014180655091438298"},
    metadata={"factura": "14814"},
)

Generate the JWS Signature

Some endpoints need a JWS Signature, in addition to your API Key, to verify the integrity and authenticity of API requests. To generate the signature, initialize the Fintoc client with the jws_private_key argument, and the SDK will handle the rest:

import os

from fintoc import Fintoc

# Provide a path to your PEM file
client = Fintoc("your_api_key", jws_private_key="private_key.pem")

# Or pass the PEM key directly as a string
client = Fintoc("your_api_key", jws_private_key=os.environ.get('JWS_PRIVATE_KEY'))

# You can now create transfers securely

Serialization

Any resource of the SDK can be serialized! To get the serialized resource, just call the serialize method!

payment_intent = client.payment_intents.list(lazy=False)[0]

serialization = payment_intent.serialize()

The serialization corresponds to a dictionary with only simple types, that can be JSON-serialized.

Acknowledgements

The first version of this SDK was originally designed and handcrafted by @nebil, ad piscolem. He built it with the help of Gianni Roberto's Picchi 2.

Metadata

Release files for fintoc 2.26.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fintoc 2.26.0
File Size Uploaded Provenance
fintoc-2.26.0.tar.gz 25.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for fintoc 2.26.0
File Interpreter ABI Platform
fintoc-2.26.0-py3-none-any.whl Python 3 none any Details

Total release size: 78.5 kB

Release files / fintoc-2.26.0.tar.gz

Download URL fintoc-2.26.0.tar.gz
Size 25.7 kB
Tags Source
SHA-256 checksum
How to use checksums
15eaa5a3aa77352c3a3b9a1e7b89a576726434d866f13eec2deb90f627e4a89a
BLAKE2b-256 checksum
How to use checksums
6b2814a97b4ad08f0a09b2d0e391970121e293329571074b5d2883fcae2f3d20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / fintoc-2.26.0-py3-none-any.whl

Download URL fintoc-2.26.0-py3-none-any.whl
Size 52.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6140cdf51a1cdb3a258ddd20491718b6489d11faa07206e59ca0d02030bc9b7e
BLAKE2b-256 checksum
How to use checksums
b427f05b99caa4981550cbbb3f1a6d98024e625d12ce27c16b6d797b528afd8c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for fintoc 2.26.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

2.26.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page