This document describes how to start a local development server and manually test all API endpoints.
- Python 3.10+
- uv package manager
- curl (for testing)
- Install dependencies:
uv sync- Configure environment:
cp .env.example .env- Edit
.envto use port 8080:
APP_PORT=8080
APP_BASE_URL=http://localhost:8080uv run uvicorn main:app --host 0.0.0.0 --port 8080Expected output:
INFO: Started server process [xxxxx]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
Open a new terminal and run the following tests.
Request:
curl -s http://localhost:8080/ | jqExpected Response:
{
"service": "Payment Link Service",
"status": "running"
}Pass Criteria: Status code 200, response contains "status": "running"
Request:
TEST_RECEIVER="0x1234567890abcdef1234567890abcdef12345678"
curl -s "http://localhost:8080/create-payment-link?amount=0.01&receiver=$TEST_RECEIVER" | jqExpected Response:
{
"payment_id": "<uuid>",
"payment_url": "http://localhost:8080/pay/<uuid>",
"amount": "0.01",
"receiver": "0x1234567890abcdef1234567890abcdef12345678"
}Pass Criteria:
- Status code 200
- Response contains
payment_id,payment_url,amount, andreceiver payment_urlmatches the formathttp://localhost:8080/pay/<payment_id>
Save the payment_id for subsequent tests:
TEST_RECEIVER="0x1234567890abcdef1234567890abcdef12345678"
PAYMENT_ID=$(curl -s "http://localhost:8080/create-payment-link?amount=0.05&receiver=$TEST_RECEIVER" | jq -r '.payment_id')
echo "Payment ID: $PAYMENT_ID"Directly query the SQLite database to confirm the payment was stored correctly.
Request:
sqlite3 payments.db "SELECT payment_id, amount, receiver, status, tx_hash FROM payments WHERE payment_id='$PAYMENT_ID';"Expected Output:
<payment_id>|0.05|0x1234567890abcdef1234567890abcdef12345678|pending|
Alternative (formatted output):
sqlite3 -header -column payments.db "SELECT payment_id, amount, receiver, status, tx_hash, created_at FROM payments WHERE payment_id='$PAYMENT_ID';"Expected Output:
payment_id amount receiver status tx_hash created_at
------------------------------------ ---------- ------------------------------------------ ---------- ---------- -------------------
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 0.05 0x1234567890abcdef1234567890abcdef12345678 pending 2024-01-01 12:00:00
Pass Criteria:
- Record exists in the database
amountmatches the requested amount (0.05)receivermatches the requested receiver addressstatusispendingtx_hashis empty/null
View all payments in the database:
sqlite3 -header -column payments.db "SELECT * FROM payments;"Request:
curl -s -w "\nHTTP Status: %{http_code}\n" "http://localhost:8080/create-payment-link?amount=-5"Expected Response:
- HTTP Status: 422
- Response contains validation error
Pass Criteria: Status code 422 (Unprocessable Entity)
Request:
curl -s -w "\nHTTP Status: %{http_code}\n" "http://localhost:8080/create-payment-link"Expected Response:
- HTTP Status: 422
- Response contains missing parameter error
Pass Criteria: Status code 422 (Unprocessable Entity)
Request:
curl -s "http://localhost:8080/status/$PAYMENT_ID" | jqExpected Response:
{
"payment_id": "<uuid>",
"amount": 0.05,
"paid": false,
"tx": null
}Pass Criteria:
- Status code 200
paidisfalsetxisnull
Request:
curl -s -w "\nHTTP Status: %{http_code}\n" "http://localhost:8080/status/nonexistent-id"Expected Response:
{
"error": "Payment not found"
}Pass Criteria: Status code 404
Request:
curl -s -w "\nHTTP Status: %{http_code}\n" "http://localhost:8080/pay/$PAYMENT_ID"Expected Response:
- HTTP Status: 402
- Response contains x402 payment requirements with
acceptsarray
Pass Criteria: Status code 402 (Payment Required)
Request:
curl -s -w "\nHTTP Status: %{http_code}\n" "http://localhost:8080/pay/nonexistent-id"Expected Response:
{
"error": "Payment not found"
}Pass Criteria: Status code 404
Request:
curl -s -w "\nHTTP Status: %{http_code}\n" \
-H "Accept: text/html" \
-H "User-Agent: Mozilla/5.0" \
"http://localhost:8080/pay/$PAYMENT_ID"Expected Response:
- HTTP Status: 400
- Response contains HTML payment page
Pass Criteria: Status code 400, response is HTML content
Run the automated tests:
uv run pytest tests/ -vExpected output:
tests/test_main.py::test_root_endpoint PASSED
tests/test_main.py::test_create_payment_link PASSED
tests/test_main.py::test_create_payment_link_invalid_amount PASSED
tests/test_main.py::test_create_payment_link_missing_amount PASSED
tests/test_main.py::test_pay_nonexistent_payment PASSED
tests/test_main.py::test_status_nonexistent_payment PASSED
tests/test_main.py::test_payment_flow_without_x402_header PASSED
tests/test_main.py::test_status_after_create PASSED
============================== 8 passed ==============================
Save this as test_endpoints.sh and run with bash test_endpoints.sh:
#!/bin/bash
BASE_URL="http://localhost:8080"
TEST_RECEIVER="0x1234567890abcdef1234567890abcdef12345678"
echo "=== Test 1: Health Check ==="
curl -s "$BASE_URL/" | head -5
echo
echo "=== Test 2: Create Payment Link ==="
RESPONSE=$(curl -s "$BASE_URL/create-payment-link?amount=0.05&receiver=$TEST_RECEIVER")
echo "$RESPONSE" | jq
PAYMENT_ID=$(echo "$RESPONSE" | jq -r '.payment_id')
echo "Saved Payment ID: $PAYMENT_ID"
echo
echo "=== Test 2b: Verify Database Record ==="
sqlite3 -header -column payments.db "SELECT payment_id, amount, receiver, status, tx_hash, created_at FROM payments WHERE payment_id='$PAYMENT_ID';"
echo
echo "=== Test 3: Invalid Amount ==="
curl -s -w "HTTP Status: %{http_code}\n" "$BASE_URL/create-payment-link?amount=-5&receiver=$TEST_RECEIVER" | head -1
echo
echo "=== Test 4: Missing Amount ==="
curl -s -w "HTTP Status: %{http_code}\n" "$BASE_URL/create-payment-link?receiver=$TEST_RECEIVER" | head -1
echo
echo "=== Test 5: Check Payment Status (Pending) ==="
curl -s "$BASE_URL/status/$PAYMENT_ID" | jq
echo
echo "=== Test 6: Status Not Found ==="
curl -s -w "HTTP Status: %{http_code}\n" "$BASE_URL/status/nonexistent-id"
echo
echo "=== Test 7: Payment Endpoint (No Header) ==="
curl -s -w "\nHTTP Status: %{http_code}\n" "$BASE_URL/pay/$PAYMENT_ID" | tail -5
echo
echo "=== Test 8: Payment Not Found ==="
curl -s -w "HTTP Status: %{http_code}\n" "$BASE_URL/pay/nonexistent-id"
echo
echo "=== All manual tests completed ==="- Stop the server with
Ctrl+C - Remove test database (optional):
rm -f payments.db