Skip to content

Commit

Permalink
feat(integration): add payment solution integration through stripe ec…
Browse files Browse the repository at this point in the history
…osystem (#511)
  • Loading branch information
neerajkrbansal1996 authored Oct 7, 2024
1 parent cc9c768 commit 5a89350
Show file tree
Hide file tree
Showing 9 changed files with 698 additions and 0 deletions.
96 changes: 96 additions & 0 deletions integrations/stripe_payment_solution/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Stripe Payment Solution

Ever had an idea to use Stripe as a payment partner for your business, That's why I've harnessed the power of Fetch.AI
Agent and Stripe payment ecosystem to develop a **Stripe Payment Solution** integration, designed to transform all your
payment requirements, into a simple and convenient manner.

## Table of Contents

- [Introduction](#introduction)
- [Features](#features)
- [How It Works](#how-it-works)
- [Installation](#installation)
- [Usage](#usage)
- [Contributing](#contributing)
- [License](#license)

## Introduction

**Stripe Payment Solution** is an innovative tool that leverages Fetch.AI's Agent technology to help anyone with a requirement to accept payment over the Internet. This System integrates Stripe as the Payment regulator for all the payment related services.

## Features

- Real Time Payment Link Generator.
- Real Time Payment Confirmation mechanism.
- Custom Multi Cart Item Payments.
- Simple UI.
- Automated Invoicing & Receipts
- One-Click Payments for Customers

## Working Diagram

![Working Diagram](./images/payment_system_overview.png "Working Diagram")

This Agent can work like a template and can be used in different organizations with their API keys from stripe A/c.


## Demo Video

https://github.com/user-attachments/assets/3de86092-e2aa-43f1-b59d-73b725698600


## Detail Document

[Detail Document](https://github.com/user-attachments/files/16706323/Stripe_Agent_Integration.pdf)


## How It Works

Stripe Payment Solution few items to choose from, for testing purposes.

1. Choose one of the items to initiate the payment.
2. Then a payment link from Stripe is generated for payment, Click it.
3. Fill it the Payment Details and click **Place Order**, wait for Payment Confirmation.

## Installation

To get started with **Stripe Payment Solution**, follow these steps:

1. **Clone the repository**:
```bash
git clone https://github.com/fetchai/uAgents.git
cd stripe-agent

2. **Open a shell**:
```bash
poetry shell
3. **Install dependencies using Poetry**:
```bash
poetry install --no-root

4. Get API Key and Endpoint Secret from [Stripe.com](https://dashboard.stripe.com/login).

5. **Run the webhook**:
```bash
cd src/stripe_webhook
poetry run python webhook.py
6. Using Ngrok or any Tunneling Software, Create secure https endpoint and set it up as a webhook in Stripe dashboard under the webhook section.
7. **Set up .env file**:
To run the demo, you need to add these API keys and URLs in .env file:
```bash
STRIPE_API_KEY='YOUR_STRIPE_KEY'
STRIPE_ENDPOINT_SECRET='YOUR_STRIPE_ENDPOINT_SECRET'
STRIPE_WEBHOOK_URL='YOUR_STRIPE_WEBHOOK_URL'

8. **Run the agent**:
```bash
cd src/stripe_agent
poetry run python agent.py
9. **Run the demo_server**:
```bash
cd src/stripe_demo_server
poetry run python app.py
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions integrations/stripe_payment_solution/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"categories": [
"Stripe",
"Payment Solution"
],
"deltav": false,
"description": "Helps User for there Payment Requirements",
"title": "Stripe Payment Solution"
}
18 changes: 18 additions & 0 deletions integrations/stripe_payment_solution/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[tool.poetry]
name = "general-use-payment-stripe-solution"
version = "0.1.0"
description = "General Use Payment Solution with Stripe and Fetch.AI Agents"
authors = ["Neeraj Bansal <[email protected]>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"
uagents = { version = "^0.15.2", python = ">=3.10,<3.13" }
uagents-ai-engine = { version = "^0.5.0", python = ">=3.10,<3.12" }
stripe = "^10.7.0"
Flask = { extras = ["async"], version = "^3.0.3" }
python-dotenv = "^1.0.1"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
157 changes: 157 additions & 0 deletions integrations/stripe_payment_solution/src/stripe_agent/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import os
import uuid

import requests
from ai_engine import UAgentResponse, UAgentResponseType
from dotenv import load_dotenv
from uagents import Agent, Protocol, Context, Model
from uagents.setup import fund_agent_if_low

class KeyValue(Model):
currency: str
product_name: str
unit_price: int
units: int

class StripePaymentRequest(Model):
item_in_cart: list[KeyValue]
customer_email: str
order_id: str

class QueryPaymentStatus(Model):
client_reference_id: str



class PaymentStatus(Model):
client_reference_id: str
data: dict

load_dotenv()

agent = Agent(
name="Stripe Agent",
seed="Stripe Agent secret seed phrase",
log_level="DEBUG",
endpoint="http://localhost:8001/submit",
port=8001
)
fund_agent_if_low(str(agent.wallet.address()))

print("Agent Address:", agent.address)


stripe_payment_protocol = Protocol("Stripe Payment Protocol", "1.00")

API_KEY = os.getenv('STRIPE_API_KEY', "")
ENDPOINT_SECRET = os.getenv('STRIPE_ENDPOINT_SECRET', "")
WEBHOOK_URL = os.getenv('STRIPE_WEBHOOK_URL', "")
STRIPE_API_URL = os.getenv('STRIPE_API_URL', "")


@stripe_payment_protocol.on_message(model=StripePaymentRequest, replies={UAgentResponse})
async def create_checkout_session(ctx: Context, sender: str, msg: StripePaymentRequest):
ctx.logger.info(
f"Received Request from {msg.customer_email} for Payment Link.")
try:
print(agent.address)
payload = {
'customer_creation': 'always',
'customer_email': msg.customer_email,
'mode': 'payment',
'payment_intent_data[metadata][order_id]': msg.order_id,
'success_url': f"{WEBHOOK_URL}/order/success?session_id={{CHECKOUT_SESSION_ID}}",
'cancel_url': f"{WEBHOOK_URL}/cancel"
}

for index, item in enumerate(msg.item_in_cart):
payload[f'line_items[{index}][price_data][currency]'] = item.currency
payload[f'line_items[{index}][price_data][product_data][name]'] = item.product_name
payload[f'line_items[{index}][price_data][unit_amount]'] = item.unit_price
payload[f'line_items[{index}][quantity]'] = item.units

headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/x-www-form-urlencoded'
}

# encoded_payload = urllib.parse.urlencode(payload, doseq=True)
response = requests.post(f"{STRIPE_API_URL}/checkout/sessions", headers=headers, data=payload)
session = response.json()
request_id = str(uuid.uuid4())
if response.status_code == 200 and 'url' in session:
resp = await ctx.send(
sender,
UAgentResponse(
message=str(session['url']),
type=UAgentResponseType.FINAL,
request_id=request_id
),
)

ctx.storage.set(msg.order_id, {'address': sender})
else:
await ctx.send(
sender,
UAgentResponse(
message="Can't generate payment link, please try again after some time.!",
type=UAgentResponseType.FINAL,
request_id=request_id
),
)
except Exception as exc:
ctx.logger.error(exc)
await ctx.send(
sender, UAgentResponse(message=str(exc), type=UAgentResponseType.ERROR)
)


@stripe_payment_protocol.on_message(model=QueryPaymentStatus, replies={UAgentResponse})
async def payment_status(ctx: Context, sender: str, msg: QueryPaymentStatus):
ctx.logger.info(
f"Received query request from {msg.client_reference_id}.")
try:
payment_details = ctx.storage.get(msg.client_reference_id) or None
if 'payment_data' in payment_details:
await ctx.send(
sender, UAgentResponse(message="Payment Succeeded", type=UAgentResponseType.FINAL)
)
else:
await ctx.send(
sender, UAgentResponse(message="Payment confirmation awaited", type=UAgentResponseType.FINAL)
)
except Exception as exc:
ctx.logger.error(exc)
await ctx.send(
sender, UAgentResponse(message=str(exc), type=UAgentResponseType.ERROR)
)


@stripe_payment_protocol.on_message(model=PaymentStatus, replies={UAgentResponse})
async def payment_status(ctx: Context, sender: str, msg: PaymentStatus):
ctx.logger.info(
f"Received Payment Update of Customer {msg.client_reference_id}.")
try:
payment_details = ctx.storage.get(msg.client_reference_id) or None
if payment_details:
payment_details['payment_data'] = msg.data
ctx.storage.set(msg.client_reference_id, payment_details)

await ctx.send(
payment_details['address'], UAgentResponse(message="Payment Succeeded", type=UAgentResponseType.FINAL)
)
print(f"Notified {payment_details['address']} of payment confirmation")
else:
print('Weird...')

except Exception as exc:
ctx.logger.error(exc)
await ctx.send(
sender, UAgentResponse(message=str(exc), type=UAgentResponseType.ERROR)
)


agent.include(stripe_payment_protocol, publish_manifest=True)

if __name__ == "__main__":
agent.run()
79 changes: 79 additions & 0 deletions integrations/stripe_payment_solution/src/stripe_demo_server/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import asyncio
from typing import List

from flask import Flask, render_template, request, jsonify
from pydantic import Field
from uagents import Model
from uagents.communication import send_sync_message


app = Flask(__name__)

class KeyValue(Model):
currency: str
product_name: str
unit_price: int
units: int

class QueryPaymentStatus(Model):
client_reference_id: str

class StripePaymentRequest(Model):
item_in_cart: list[KeyValue]
customer_email: str
order_id: str


@app.route('/', methods=['GET'])
def index():
return render_template('index.html')


@app.route('/test', methods=['GET'])
def test():
return jsonify({"message": "Flask server is running"}), 200


def run_async(coro):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
return loop.run_until_complete(coro)


@app.route('/query', methods=['POST'])
async def query_agent():
payment_status = QueryPaymentStatus(
client_reference_id='123456'
)
response = await send_sync_message(
'agent1qtehcv05d2yfdxgyhk8wnk9pavl7yxyzg2m05gvqwgggwtxas99nugry6xk',
payment_status
)
print(response)

return jsonify(response)


@app.route('/process', methods=['POST'])
async def process():
data = request.json

# Create a StripePaymentRequest object
payment_request = StripePaymentRequest(
item_in_cart=data['item_in_cart'],
customer_email=data['customer_email'],
order_id=data['order_id']
)
print("sending the payment request to Stripe agent")

response = await send_sync_message(
'agent1qtehcv05d2yfdxgyhk8wnk9pavl7yxyzg2m05gvqwgggwtxas99nugry6xk',
payment_request
)
print(response)

return jsonify(response)


if __name__ == '__main__':
app.run(debug=True, port=9000, host='0.0.0.0')
Loading

0 comments on commit 5a89350

Please sign in to comment.