Project

General

Profile

Edit Copy Actions

Feature #3933

closed

Payment Initiation for Zelle Payment

Added by Sreenivas Pisupati 3 months ago. Updated 15 days ago.

Status:
Closed
Priority:
Normal
Assignee:
Start date:
09/14/2025
Due date:
% Done:

40%

Estimated time:
192:00 h
Spent time:

Description

General:
We are developing Payment Initiation feature for sending and receiving payments through a Zelle-connected bank partner behind a Payments API.
The following components are planned as part of this feature.
Payment Orchestrator
Bank Client (httpx)
Webhook Receiver (FastAPI)
Observability
> payment_id and client_ref across logs.
> Status metrics (initiated, completed, returned, retry counts, webhook latency).


Add

Subtasks


Add

Related issues

Updated by Sreenivas Pisupati 3 months ago

Please add estimated time

Updated by Yogeesh sai 3 months ago

  • Estimated time set to 192:00 h

Payment Orchestrator Implementation: 2 days
Bank Client (httpx) Setup: 1 day
Webhook Receiver (FastAPI): 1.5 days
Observability (logging + metrics): 1.5 days
Integration & Testing (end-to-end flow): 2 days
Total Estimated Time:8 days (full cycle from development → testing → ready for QA).

Updated by Yogeesh sai 3 months ago

  • % Done changed from 0 to 40

Customer → POS → Generates TX1234 & shows Zelle info

Customer sends Zelle payment

Plaid polls → Bank → New transaction (Zelle, $25.00, TX1234)

Backend checks → Match found → POS: "Payment Confirmed"

Updated by Yogeesh sai 3 months ago

Client App → Payments API → Payment Orchestrator

Bank Client (httpx → Bank Partner API)

Bank Partner (Zelle rails)

Counterparty Bank/Zelle

Webhook Receiver (FastAPI)

Payment Orchestrator (update status)

Observability (metrics + logs)

Updated by Yogeesh sai 2 months ago

1. Payment Orchestrator

Role: Central brain for initiating and managing payments.

Responsibilities:

Accepts a payment initiation request (e.g., {amount, recipient, client_ref}).

Generates a payment_id (UUID).

Calls Bank Client to send payment to partner bank’s API.

Tracks lifecycle states: initiated → processing → completed/returned.

Handles retries (e.g., if partner bank API is down).

Persists state to database (payments table).

2. Bank Client (httpx)

Role: Abstraction over the partner bank’s Payments API.

Responsibilities:

Handle auth (OAuth2, mTLS, API key depending on Chase/partner requirements).

Send payment initiation requests via HTTP.

Map responses to internal schema (payment_id, status, bank_ref).

Include resiliency: timeout, retries, circuit breaker (httpx supports retries).

Example:

async with httpx.AsyncClient() as client:
resp = await client.post(
bank_url + "/payments",
headers={"Authorization": f"Bearer {token}"},
json=payload
)

3. Webhook Receiver (FastAPI)

Role: Handle async notifications from bank/Zelle (e.g., payment completed, returned).

Responsibilities:

Expose /webhook/payments.

Verify auth/signature from partner bank.

Parse payload and update local DB (payment_id, status, timestamps).

Ack quickly with 200 OK.

Queue heavy processing (e.g., ERP updates) to async workers.

Example (FastAPI):

from fastapi import FastAPI, Request

app = FastAPI()

@app.post("/webhook/payments")
async def payment_webhook(req: Request):
body = await req.json()
payment_id = body["payment_id"]
status = body["status"] # Update DB with new status
return {"ok": True}

4. Observability

Logs:

Every log line includes payment_id and client_ref.

Example:

{"level":"info","payment_id":"1234","client_ref":"INV-1002","msg":"Payment initiated"}

Metrics (Prometheus / OpenTelemetry):

payment_status_total{status="initiated"}

payment_status_total{status="completed"}

payment_status_total{status="returned"}

payment_retry_count{payment_id="1234"}

payment_webhook_latency_seconds{}

Tracing (OpenTelemetry + Jaeger/Tempo):

Trace spans: PaymentOrchestrator → BankClient → WebhookReceiver.

Propagate payment_id + client_ref as trace attributes.

🔹 Payment Lifecycle Example

Initiation:
Client → Orchestrator → Bank Client → Bank API → initiated.
Log: {"payment_id":"123","status":"initiated"}

Webhook:
Bank → Webhook Receiver → DB update → Orchestrator marks completed.
Log: {"payment_id":"123","status":"completed"}

Metrics:

payment_status_total{status="initiated"}++

Later payment_status_total{status="completed"}++

Webhook latency recorded.

🔹 Suggested Tech Stack

FastAPI → Orchestrator + Webhook service.

httpx → Bank client.

SQLAlchemy / Postgres → Persistence for payments.

Celery / RQ → For async retries & background jobs.

Prometheus + Grafana → Metrics.

OpenTelemetry + Jaeger → Tracing.

Structured JSON logging → For correlation.

Actions #6

Updated by Yogeesh sai about 2 months ago

  • Status changed from New to Resolved
Actions #7

Updated by Yogeesh sai 15 days ago

  • Status changed from Resolved to Closed
Edit Copy Actions

Also available in: Atom PDF