Skip to content

Example implementation

When building a custom API integration with iwocaPay, your customer will follow a straightforward flow:

  • Redirect the customer to iwocaPay.
  • Reconcile the order with your back end.

You’ll only need to implement two or three key functions to handle these steps. For reconciliation, use webhooks to receive updates as they happen.

Below are example integrations in Python, PHP, and TypeScript. They are meant as a guide to help you get started; they are not intended to be used without adaptation and extension in a production environment. In particular, consider:

  • Integration with your existing database or back-end systems
  • Authentication or user-specific business logic
  • Error handling and logging mechanisms
  • Deployment in a secure and scalable environment

This is an example customer flow between your checkout and the iwocaPay checkout.

A customer clicks "Checkout with iwocaPay"

You redirect the user to order_url

Display the correct messaging to your customer via your checkout

Reconcile the order status with your backend

We redirect the customer to redirect_url

We send you a webhook

We redirect the customer to redirect_url

generate_order()

iwocaPay checkout

Customer checks out

Handle order state

process_webhook()

Your checkout

Customer abandons the order

  • Directorysrc
    • Directoryconfig
      • env.py
    • Directoryservices
      • iwoca_pay.py
    • Directorywebhooks
      • order_webhook_handler.py
    • Directorymodels
      • iwoca_pay.py
    • Directoryutils
      • http_client.py
    • main.py
  • .env
.env
IWOCAPAY_SUPPLIER_ACCESS_TOKEN=access_token
IWOCAPAY_SUPPLIER_UUID=uuid
IWOCAPAY_API_TOKEN=api_token
IWOCAPAY_API_URL=https://stage.iwoca-dev.co.uk/api/lending/edge/
src/config/env.py
from pydantic import BaseSettings
class Settings(BaseSettings):
IWOCAPAY_API_URL: str
IWOCAPAY_SUPPLIER_ACCESS_TOKEN: str
IWOCAPAY_SUPPLIER_UUID: str
class Config:
env_file = ".env"
settings = Settings()
if not (settings.IWOCAPAY_API_URL and settings.IWOCAPAY_SUPPLIER_ACCESS_TOKEN and settings.IWOCAPAY_SUPPLIER_UUID):
raise ValueError("Environment variables are not properly configured.")
src/services/iwoca_pay.py
from src.utils.http_client import http_client
from src.models.iwoca_pay import CreateOrderRequest, CreateOrderResponse, GetOrderStatusResponse
class IwocaPayService:
def __init__(self, supplier_uuid: str):
self.supplier_uuid = supplier_uuid
def create_order(self, request: CreateOrderRequest) -> CreateOrderResponse:
endpoint = f"/ecommerce/seller/{self.supplier_uuid}/order/"
response = http_client.post(endpoint, {"data": request.dict()})
return CreateOrderResponse(**response)
def get_order_status(self, order_id: str) -> GetOrderStatusResponse:
endpoint = f"/ecommerce/order/{order_id}/"
response = http_client.get(endpoint)
return GetOrderStatusResponse(**response)
src/webhooks/order_webhook_handler.py
from fastapi import APIRouter, Request
from src.models.iwoca_pay import WebhookPayload
router = APIRouter()
@router.post("/webhook")
async def handle_order_webhook(request: Request):
payload = WebhookPayload(**(await request.json()))
# Process the webhook data (e.g., update order status in the database)
print("Received webhook:", payload)
# Example: Handle specific statuses
if payload.data["status"] == "CREATED":
print(f"Order {payload.data['order_id']} has been created.")
else:
print(f"Unhandled order status: {payload.data['status']}")
return {"message": "Webhook processed"}
src/models/iwoca_pay.py
from pydantic import BaseModel, Field
from typing import List, Optional
class CreateOrderRequest(BaseModel):
amount: float = Field(..., description="The total amount for the order.")
reference: str = Field(..., description="A unique reference for the order.")
allowed_payment_terms: Optional[List[str]] = Field(
None, description="Optional list of allowed payment terms, e.g., ['PAY_LATER']"
)
class PricingDetails(BaseModel):
representative_interest: float = Field(..., description="Representative interest rate.")
promotions: List[dict] = Field(..., description="List of promotions, if any.")
class CreateOrderResponseData(BaseModel):
id: str = Field(..., description="Unique identifier for the order.")
amount: float = Field(..., description="The total amount for the order.")
reference: str = Field(..., description="A unique reference for the order.")
order_url: str = Field(..., description="The URL for the order checkout.")
status: str = Field(..., description="The current status of the order.")
allowed_payment_terms: List[str] = Field(
..., description="List of allowed payment terms returned by iwocaPay."
)
class CreateOrderResponse(BaseModel):
data: CreateOrderResponseData
class GetOrderStatusResponseData(BaseModel):
id: str = Field(..., description="Unique identifier for the order.")
amount: float = Field(..., description="The total amount for the order.")
reference: str = Field(..., description="A unique reference for the order.")
redirect_url: str = Field(..., description="URL to redirect the user to after checkout.")
pricing: PricingDetails = Field(..., description="Details about pricing and promotions.")
pay_link_id: str = Field(..., description="Unique ID for the payment link.")
seller_name: str = Field(..., description="Name of the seller.")
status: str = Field(..., description="The current status of the order.")
allowed_payment_terms: List[str] = Field(
..., description="List of allowed payment terms for the order."
)
class GetOrderStatusResponse(BaseModel):
data: GetOrderStatusResponseData
class WebhookPayloadData(BaseModel):
order_id: int = Field(..., description="Unique identifier for the order.")
amount: float = Field(..., description="The total amount for the order.")
reference: str = Field(..., description="A unique reference for the order.")
status: str = Field(..., description="The current status of the order.")
class WebhookPayload(BaseModel):
data: WebhookPayloadData
src/utils/http_client.py
import requests
from src.config.env import settings
class HttpClient:
def __init__(self, base_url: str, token: str):
self.base_url = base_url
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
def post(self, endpoint: str, data: dict) -> dict:
response = requests.post(f"{self.base_url}{endpoint}", json=data, headers=self.headers)
response.raise_for_status()
return response.json()
def get(self, endpoint: str) -> dict:
response = requests.get(f"{self.base_url}{endpoint}", headers=self.headers)
response.raise_for_status()
return response.json()
http_client = HttpClient(settings.IWOCAPAY_API_URL, settings.IWOCAPAY_SUPPLIER_ACCESS_TOKEN)
src/main.py
from fastapi import FastAPI
from src.services.iwoca_pay import IwocaPayService
from src.models.iwoca_pay import CreateOrderRequest
from src.webhooks.order_webhook_handler import router as webhook_router
from src.config.env import settings
app = FastAPI()
iwoca_pay_service = IwocaPayService(supplier_uuid=settings.IWOCAPAY_SUPPLIER_UUID)
# Include webhook routes
app.include_router(webhook_router)
@app.post("/create-order")
async def create_order(request: CreateOrderRequest):
try:
response = iwoca_pay_service.create_order(request)
return response
except Exception as e:
return {"error": str(e)}
@app.get("/order-status/{order_id}")
async def get_order_status(order_id: str):
try:
response = iwoca_pay_service.get_order_status(order_id)
return response
except Exception as e:
return {"error": str(e)}