Architecture Overview
AWS Bedrock Agents use action groups to call external APIs. Each action group has two parts: an OpenAPI schema that describes the available operations, and an executor (Lambda function) that performs the actual API call. Here's the flow for PodClaw:
- Bedrock Agent receives a natural language instruction (e.g. "publish today's episode")
- Agent reasoning decides to call the
publish_episode action
- Lambda executor is invoked with the episode parameters
- Lambda calls PodClaw REST API and returns the result to the agent
- Agent uses the result to formulate its final response
Step 1: OpenAPI Schema for the Action Group
Upload this schema when creating the action group in the Bedrock console. It describes the two PodClaw operations your agent will use:
yaml — podclaw-action-group.yaml
openapi: "3.0.0"
info:
title: PodClaw API
version: "1.0"
description: Publish podcast episodes to Apple Podcasts, Spotify, and 20+ directories.
paths:
/shows:
post:
operationId: create_show
summary: Create a new podcast show
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [title, description]
properties:
title:
type: string
description: The podcast show title
description:
type: string
description: A short description of the show
category:
type: string
description: Podcast category (e.g. Technology, Business)
default: Technology
responses:
"200":
description: Show created
content:
application/json:
schema:
type: object
properties:
show_id:
type: string
rss_url:
type: string
/shows/{show_id}/episodes:
post:
operationId: publish_episode
summary: Publish a podcast episode
parameters:
- name: show_id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [title, audio_url]
properties:
title:
type: string
description: Episode title
audio_url:
type: string
description: Publicly accessible URL of the MP3/M4A audio file
description:
type: string
description: Episode show notes or description
status:
type: string
enum: [published, scheduled]
default: published
responses:
"200":
description: Episode published
content:
application/json:
schema:
type: object
properties:
episode_id:
type: string
episode_url:
type: string
Step 2: Lambda Executor Function
Bedrock calls this Lambda with an event that includes the actionGroup, apiPath, and parameters. The Lambda routes the call to PodClaw and returns the response in Bedrock's expected format.
python — lambda_function.py
import json
import os
import boto3
import urllib.request
PODCLAW_API_KEY = os.environ.get("PODCLAW_API_KEY")
BASE_URL = "https://podclaw.io/api"
def call_podclaw(method, path, body=None):
url = BASE_URL + path
data = json.dumps(body).encode() if body else None
req = urllib.request.Request(
url,
data=data,
headers={
"Authorization": f"Bearer {PODCLAW_API_KEY}",
"Content-Type": "application/json",
},
method=method,
)
with urllib.request.urlopen(req, timeout=30) as resp:
return json.loads(resp.read())
def lambda_handler(event, context):
action_group = event.get("actionGroup")
api_path = event.get("apiPath")
http_method = event.get("httpMethod", "POST").upper()
parameters = event.get("parameters", [])
request_body = event.get("requestBody", {})
# Parse path parameters
path_params = {p["name"]: p["value"] for p in parameters if p.get("in") == "path"}
# Parse body properties
body_props = {}
if request_body:
for media_type in request_body.get("content", {}).values():
for prop in media_type.get("properties", []):
body_props[prop["name"]] = prop["value"]
# Route to the right PodClaw endpoint
if api_path == "/shows" and http_method == "POST":
result = call_podclaw("POST", "/shows", body_props)
response_body = {"show_id": result["id"], "rss_url": result.get("rss_url", "")}
elif "/episodes" in api_path and http_method == "POST":
show_id = path_params.get("show_id", "")
result = call_podclaw("POST", f"/shows/{show_id}/episodes", body_props)
response_body = {
"episode_id": result["id"],
"episode_url": result.get("url", ""),
}
else:
response_body = {"error": "Unknown action"}
return {
"messageVersion": "1.0",
"response": {
"actionGroup": action_group,
"apiPath": api_path,
"httpMethod": http_method,
"httpStatusCode": 200,
"responseBody": {
"application/json": {"body": json.dumps(response_body)}
},
},
}
Security: Store your PodClaw API key in AWS Secrets Manager and retrieve it at cold start using boto3.client('secretsmanager').get_secret_value(). Set the Lambda environment variable PODCLAW_API_KEY only for local testing — never in production.
Step 3: Create the Action Group
In the AWS Bedrock console, open your Agent → Action Groups → Create. Set:
- Action group name:
PodClawPublisher
- Action group type: Define with API schemas
- API schema: Upload the YAML file from Step 1
- Lambda function: Select the function from Step 2
Then update the agent instructions to include: "When asked to publish a podcast episode, use the PodClawPublisher action group."