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, you can either:

  • Use webhooks to receive updates as they happen (recommended), or:
  • Poll for updates on the order (not-recommended).

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

Customer flow

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.")
pay_link_id: str = Field(..., description="Unique ID for the payment link.")
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)}