Blog
Guides

How to keep API keys out of your Python scripts

DK
Dan Kowalsky
Founder ·

Almost every useful automation needs a key: a Stripe key, a database URL, a CRM token. The quick way to make a script work is to paste the key into it, and that's how keys end up in git history, shared notebooks and Slack threads.

Callables keeps keys out of your code and away from the people who run your functions.

Declare what the function needs

List the environment variables a function needs in secrets, and read them with os.environ:

import os

import stripe

from callables import deploy


@deploy(title="Refund an order", secrets=["STRIPE_KEY"])
def refund(charge_id: str) -> str:
    """Refunds a charge in full."""
    stripe.api_key = os.environ["STRIPE_KEY"]
    stripe.Refund.create(charge=charge_id)
    return f"Refunded {charge_id}."

The code only names the secret. The value never appears in your repo.

Set the value once

After you push, open the project in the web app and set STRIPE_KEY. Values are stored encrypted and passed to the function as environment variables each time it runs.

The people who run the function never see the value. They see a form and a result. If a declared secret hasn't been set yet, the function still runs without it, and builders see a "missing secrets" warning on the project so it's easy to spot.

Share secrets across related functions

When several functions use the same keys, put them in a group and declare the secrets once:

from callables import Group

billing = Group("billing", title="Billing", secrets=["STRIPE_KEY"])


@billing.deploy(title="Refund an order")
def refund(charge_id: str) -> str: ...


@billing.deploy(title="Find a customer")
def find_customer(email: str) -> list[dict]: ...

Every action in the group gets STRIPE_KEY, and each can declare more of its own. See groups.

Optional secrets and key files

  • Optional secrets: declare it, then read it with os.environ.get("NAME") and handle it being missing.
  • Key files, like a .pem file or a service account JSON: each secret is a single value, so paste the file's contents as the secret, and have your code read it from the variable.

Testing locally

On your own machine, the same variables come from your environment, so a .env file works well for call local. Keep .env in .gitignore.

Rules worth keeping

  • Never hard-code a key, even "just for testing".
  • Never take a key as a form input. Anyone running the function would have to know it.
  • Give each automation the narrowest key that works, like a restricted Stripe key, rather than an admin key.

Turn your scripts into tools your team can run

Add @deploy to a Python function and push. Your team gets a form, schedules and run history.

See how it works