---
title: "Add to existing project"
description: "Take a Python service that already posts webhooks by hand and move one ad-hoc HTTP call onto a generated, typed Repost sender in about 15 minutes."
---


<RepostHighlight />

You already have a service that posts webhooks to your customers with `requests` or `httpx` and a hand-built JSON body. This guide replaces one of those calls with a generated, typed sender: no rewrite, no big bang. Set aside about 15 minutes.

You start from something like this, scattered wherever an event happens:

```python
# The ad-hoc send you have today.
requests.post(
    customer.webhook_url,
    json={"type": "user.created", "data": {"id": user.id, "email": user.email}},
)
```

Python 3.10 or later is required. The client is for trusted server-side code: it holds a publish credential.

<Steps>
  <Step title="Install the CLI and runtime">
    Add the CLI and the `repost-client` runtime to your existing project.

    <CodeGroup>
      ```bash CLI install script
      curl -fsSL https://repost.sh/install | sh
      ```

      ```bash CLI from npm
      npm install -g @repost/cli
      ```

      ```bash Runtime from PyPI
      python -m pip install repost-client
      ```
    </CodeGroup>
  </Step>

  <Step title="Initialize a schema in your repo">
    From the repository root:

    ```bash
    repost schema init --language python --output ./repost_sdk
    ```

    This creates a `repost/` workspace, a `.env` file for your key, and a starter schema. Python requires an explicit `output`; its final directory name becomes the importable package, `repost_sdk` here.
  </Step>

  <Step title="Model the event you already send">
    Edit `repost/schema.repost` so the model and event match the payload your ad-hoc call sends today. For the `user.created` example above:

    ```repost repost/schema.repost
    generator sdk {
      language = "python"
      output   = "../repost_sdk"
    }

    model User {
      id    String
      email String
    }

    type User {
      created
    }

    event UserCreated {
      type      @type(User.created)
      data      User
      timestamp DateTime
    }
    ```

    Add one field per key you send today. [Schema](/docs/send/schema) covers enums, nested models, and more.
  </Step>

  <Step title="Record the schema and generate">
    ```bash
    repost schema migrate dev --name init
    ```

    This records the first migration and generates the Python package. Commit both the `repost/` and `repost_sdk/` directories. [Code generation](/docs/send/python/generation) explains the CI drift check.
  </Step>

  <Step title="Connect an environment">
    Create an environment in the [dashboard](https://app.repost.sh), copy its publish API key into `.env`, then sign in and deploy the migration:

    ```bash
    repost auth login
    repost schema migrate deploy
    ```

    Load `.env` through your framework or process manager. The runtime reads `REPOST_SEND_API_KEY`, then `REPOST_TOKEN`.
  </Step>
</Steps>

## Replace the ad-hoc call

Swap the raw `requests.post` for the generated sender. Repost fans the event out to the customer's registered endpoints, so you no longer track `webhook_url` yourself:

```python
from repost_sdk import RepostClient, User

with RepostClient() as repost:
    result = repost.webhooks.user.created(
        customer_id="customer_123",
        data=User(id="user_123", email="ada@example.com"),
        idempotency_key="user_123:created",
    )
    print(result.id)  # msg_...
```

Generated methods and models catch unknown members, missing fields, and incompatible values in your editor and type checker, and the runtime validates again before opening a connection. The idempotency key is optional; pass a business-stable key when your queue or process may repeat the logical send.

Create one client for a process and close it during shutdown. A context manager is convenient for scripts; long-running apps should use their framework lifecycle.

## Verify delivery

Trigger the code path that fires the event, then open the [dashboard](https://app.repost.sh). The send appears in the event stream with its `msg_...` id and per-endpoint delivery status. Once you trust it, delete the old `requests.post` call and repeat for the next event type.

## Continue

<Columns cols={3} className="gap-y-4">
  <Card title="Code generation" icon="cog" href="/docs/send/python/generation" cta="Generation" arrow="true">
    Generated package contents, regeneration, and version checks.
  </Card>

  <Card title="Model your events" icon="table" href="/docs/send/schema" cta="Schema" arrow="true">
    Enums, nested models, and the full schema language.
  </Card>

  <Card title="Reliability" icon="shield-check" href="/docs/send/python/reliability" cta="Outcomes" arrow="true">
    Idempotency, delivery states, cancellation, and retries.
  </Card>
</Columns>
