This example demonstrates how to use HumanLayer webhooks with FastAPI.
This example uses a "purchase materials" endpoint that requires human approval.
The workflow is:
- open http://localhost:8000/purchase-materials
- this will create a pending approval in humanlayer for
{"material": "wood", "quantity": 10} - upon approval of the proposed action, a webhook will be sent to the
/webhook/inboundendpoint - if the action is approved, the purchase will be finalized
The server tracks the state of approvals in memory, you can view it at http://localhost:8000/purchases
This is obviously a bit of a toy example, but you can use it to see how webhooks work with HumanLayer.
-
Create a virtual environment and activate it:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Copy
.env.exampleto.envand fill in your API keys:cp .env.example .env # Add your keys to .env: # HUMANLAYER_API_KEY=your_key_here
-
Get an ngrok.com account and claim your free static subdomain.
-
Set up response webhooks in the HumanLayer saas
Start the server:
python app.py
# Or
uvicorn app:app --reloadIn another terminal, run ngrok:
ngrok http 8000 --domain=your-subdomain.ngrok-free.app- Open http://localhost:8000/purchase-materials - this will queue a purchase for approval
- Open http://localhost:8000/purchases - this will show the pending approval
- Approve the purchase w/ HumanLayer - in this example we'll use the slack integration
- Open http://localhost:8000/purchases - this will show the purchase was finalized
- You can check the app logs to see that the webhook was received and the purchase was executed
The code that handles this is in app.py:
@app.post("/webhook/inbound")
async def webhook_inbound(webhook: FunctionCall) -> Dict[str, str]:
purchases[webhook.call_id] = webhook
if webhook.status is not None and webhook.status.approved:
finalize_purchase(webhook.spec.kwargs["material"], webhook.spec.kwargs["quantity"])
else:
print(f"Purchase {webhook.call_id} denied")
return {"status": "ok"}




