Villa Backend SDK — User Manual
Python SDK and CLI for the Villa Market backend: Cognito login, order building, validation, and card payment.
1. Install
pip install villa-market-backend-sdk
Development (from git):
git clone https://github.com/villa-market/villa-backend-sdk-1.git
cd villa-backend-sdk-1
pip install -e ".[dev]"
Verify:
villa --version
python -c "from villa_backend_sdk import VillaClient; print('OK')"
2. Configure environment
Copy the example file and set your Cognito client secret:
cp .env.example .env
# Edit .env — paste value from Cognito → Show client secret
set -a && source .env && set +a
| Variable | Required | Description |
|---|---|---|
VILLA_COGNITO_CLIENT_ID | Yes | Cognito app client ID |
VILLA_COGNITO_USER_POOL_ID | Yes | Cognito user pool ID |
VILLA_COGNITO_CLIENT_SECRET | Yes* | App client secret (*confidential clients) |
VILLA_COGNITO_REGION | No | Default ap-southeast-1 |
VILLA_BASE_URL | No | Default https://shop.villamarket.com |
VILLA_ENV | No | dev or prod (default dev) |
VILLA_CUSTOMER_ID | No | Default customer / owner ID |
VILLA_MID | No | KBank merchant ID |
**Dev app client (villa-backend-sdk-dev):**
| Setting | Value |
|---|---|
| User pool | villaMembers2 (ap-southeast-1_bul3MgmNE) |
| Client ID | 6k932iah7v1hgnd33a53c3v1mj |
| Region | ap-southeast-1 |
Cognito app client must have **Username and password** (ALLOW_USER_PASSWORD_AUTH) enabled.
3. Authenticate (Cognito)
All Villa backend API calls require a Cognito **ID token** as Authorization: Bearer <token>.
Python — login
from villa_backend_sdk import VillaClient
client = VillaClient.from_env()
tokens = client.login("user@example.com", "your-password")
# ID token is now attached to client HTTP calls automatically
print(tokens.id_token[:40], "...")
Python — verify ID token
Use this before trusting a stored JWT or when your backend receives a token from a client:
from villa_backend_sdk import VillaClient
client = VillaClient.from_env()
# Verify a token string
verified = client.verify_id_token(tokens.id_token)
print(verified.sub, verified.email, verified.exp)
# Or after login, verify the token currently on the client
client.login("user@example.com", "your-password")
assert client.is_id_token_valid() is True
verified = client.verify_id_token() # uses the logged-in token
CLI:
villa auth verify-token --token "$ID_TOKEN"
Verification checks JWT signature against Cognito JWKS, plus exp, iss, aud, and token_use=id.
Python — register new user (SignUp)
No AWS admin IAM needed — same API your chat app uses:
client = VillaClient.from_env()
result = client.register(
"newuser@example.com",
"SecurePass123!",
email="newuser@example.com",
)
print(result.user_confirmed) # False until email confirmed
# After user enters email code:
client.auth.confirm_sign_up("newuser@example.com", confirmation_code="123456")
tokens = client.login("newuser@example.com", "SecurePass123!")
CLI — login
villa auth login --username user@example.com --password 'your-password'
Smoke test (shared dev account)
python3 scripts/smoke_test_cognito_login.py
Shared test credentials (safe to commit): see COGNITO_TEST.md.
4. Build an order
Orders follow the villaMasterSchema contract.
from villa_backend_sdk import OrderBuilder
order = (
OrderBuilder()
.with_ids(order_id="order-1", owner_id="owner-1", basket_id="basket-1")
.with_branch("1000")
.add_product(cprcode=25281, quantity=1)
.with_delivery_shipping(
shipping_postcode="10330",
shipping_phone="0812345678",
shipping_address="123 Sukhumvit Rd",
)
.with_payment_totals(grand_total=174.0)
.build()
)
Generate an order ID from the backend:
generated = client.orders.generate_order_id("1000")
created = client.orders.create(order)
fetched = client.orders.get(created.order_id)
5. Validate before payment
Always validate locally and remotely before charging a card.
# 1. Local JSON Schema check (bundled order.yaml)
client.schema_validator.validate_order(order.to_api_payload())
# 2. Remote pricing APIs
result = client.pre_payment.validate(
order,
expected_grand_total=174.0,
)
print(result.valid, result.errors, result.calculated_grand_total)
if not result.valid:
raise SystemExit("Fix order before payment")
| Step | API path | Purpose |
|---|---|---|
| Local schema | bundled order.yaml | Structure / required fields |
| Grand total | /api/webPayment/calculateGrandtotal | Verify totals |
| Cost | /api/calculateCost/getCost | Verify cart pricing |
6. Pay with card
token = client.payments.create_card_token(
client.payments.build_card_token_request(
order_id=order.order_id,
basket_id=order.basket_id,
grand_total=str(result.calculated_grand_total or 174),
)
)
payment = client.payments.initiate_card_payment(
client.payments.build_card_payment_request(
order_id=order.order_id,
basket_id=order.basket_id,
grand_total=str(result.calculated_grand_total or 174),
token=token.card_token,
)
)
print(payment.redirect_url)
Dev environment uses /api/payment3devapi/* paths automatically when VILLA_ENV=dev.
7. Full checkout example
from villa_backend_sdk import VillaClient, OrderBuilder
client = VillaClient.from_env()
client.login("user@example.com", "your-password")
order = (
OrderBuilder()
.with_ids(order_id="order-1", owner_id="owner-1", basket_id="basket-1")
.with_branch("1000")
.add_product(cprcode=25281, quantity=1)
.with_payment_totals(grand_total=174.0)
.build()
)
check = client.pre_payment.validate(order, expected_grand_total=174.0)
if check.valid:
token = client.payments.create_card_token(
client.payments.build_card_token_request(
order_id=order.order_id,
basket_id=order.basket_id,
grand_total="174",
)
)
print("Token:", token.card_token)
8. CLI reference
Global options (also read from env vars):
villa --env dev --customer-id OWNER_ID --merchant-id MERCHANT_ID <command>
| Command | Description |
|---|---|
villa health | Check backend reachability |
villa config show | Print active SDK config |
villa auth login | Cognito login |
villa order generate-id --branch-id 1000 | Generate order ID |
villa order get ORDER_ID | Fetch order |
villa order validate-schema --file order.json | Local schema validation |
villa validate pre-payment --file order.json --expected-grand-total 500 | Pre-payment checks |
villa payment charge --order-id ... --basket-id ... --amount 174 | Card payment flow |
Examples:
villa health
villa config show
villa auth login --username user@example.com --password 'secret'
villa order validate-schema --file tests/fixtures/goodSample.json
villa validate pre-payment --file tests/fixtures/goodSample.json --expected-grand-total 500
villa --env dev payment charge \
--order-id order-1 \
--basket-id basket-1 \
--amount 174 \
--validate \
--order-file tests/fixtures/goodSample.json
9. Run tests
pytest tests/unit -m unit # fast, mocked
pytest tests/integration -m integration # uses real Cognito login + JWT
pytest # full suite (72 tests)
Integration tests log in with the shared test account and attach JWT to all API calls.
10. Troubleshooting
| Symptom | Fix |
|---|---|
Unable to verify secret hash | Use **Show client secret** value, not the Client Secret ID |
User is not confirmed | Confirm via email code or Cognito console → Users → Confirm |
USER_PASSWORD_AUTH flow not enabled | Enable **Username and password** on app client |
401 on API calls | Call client.login() first; check token expiry (60 min) |
| Integration tests fail on login | Set Cognito env vars; confirm test user |
11. Related docs
Repository: github.com/villa-market/villa-backend-sdk-1