B
<h2 id="introduction">Introduction</h2>
If you want to deliver video content securely and restrict access to paying users only, you can build your own serverless infrastructure instead of using expensive off-the-shelf solutions. In this guide, we explore how the "Cloud With Betsy" project built a cost-effective and high-performance video platform.
<h2 id="architecture-overview">Architecture Overview</h2>
Our platform is designed with a serverless architecture. Key components include:
* **SST (Serverless Stack):** To manage AWS infrastructure as code (IaC) and deploy the Next.js application.
* **AWS Lambda:** To execute business logic (webhook processing, token validation).
* **Amazon DynamoDB:** To store user and access token information.
* **LemonSqueezy:** For payment processing and webhook triggers.
* **ConvertKit:** To send access links to users via email.
* **Vimeo:** To host and stream videos (chosen over AWS S3/MediaConvert for simplicity).
<h2 id="step-1-purchase">Step 1: Purchase Flow and Webhook</h2>
When a user completes a purchase on LemonSqueezy, a webhook is triggered. This webhook sends a request to our AWS Lambda function.
Setting this up with SST is straightforward:
// sst.config.ts example
const hookFunction = new Function(stack, 'lemon-hook', {
handler: 'packages/services/functions/webhooks/lemon.handler',
url: true, // Create Public URL
bind: [CONVERTKIT_API_KEY, ordersTable], // Environment variables and table access
});
<h2 id="step-2-token-db">Step 2: Access Token and Database</h2>
Our Lambda function processes the incoming webhook data and generates a unique **video access token**. This token and the user details are saved to an Amazon DynamoDB table.
// Lambda Handler (Simplified)
export const handler = async (event) => {
const body = JSON.parse(event.body);
const userEmail = body.data.attributes.user_email;
const videoToken = generateUniqueToken(); // Token generation function
// Save to DynamoDB
await dynamoDb.put({
TableName: Table.orders.tableName,
Item: {
pk: `USER#${userEmail}`,
sk: `ORDER#${body.data.id}`,
videoToken: videoToken,
createdAt: Date.now(),
},
});
// Add subscriber to ConvertKit and assign token as custom field
await convertKit.addSubscriber(userEmail, { video_token: videoToken });
};
<h2 id="step-3-email">Step 3: Sending Access Link to User</h2>
Once the token is created, an automation on ConvertKit is triggered. This automation sends a personalized email to the user. The link in the email contains the user's token:
`https://yourplatform.com/watch?token=USER_TOKEN`
<h2 id="step-4-delivery">Step 4: Content Delivery and Validation</h2>
When the user clicks the link, our Next.js application opens.
1. The token is retrieved from the URL (via `useEffect` or server-side).
2. An API route (Lambda) is called to validate the token against DynamoDB.
3. If the token is valid, Vimeo embed codes (or private links) are fetched and displayed.
4. If the token is invalid or expired, an error message is shown.
This method ensures that even if direct links are shared, content cannot be accessed without token validation (you can further enhance security by restricting domains on Vimeo).
<h2 id="conclusion">Conclusion</h2> With this architecture, you can build a secure video platform with zero server management costs (Scale to Zero), paying only for what you use. Leveraging the power of SST and AWS allows you to focus on your product rather than infrastructure complexity. <div class="toc"> <ul> <li><a href="#introduction">Introduction</a></li> <li><a href="#architecture-overview">Architecture Overview</a></li> <li><a href="#step-1-purchase">Step 1: Purchase Flow and Webhook</a></li> <li><a href="#step-2-token-db">Step 2: Access Token and Database</a></li> <li><a href="#step-3-email">Step 3: Sending Access Link to User</a></li> <li><a href="#step-4-delivery">Step 4: Content Delivery and Validation</a></li> <li><a href="#conclusion">Conclusion</a></li> </ul> </div> <p>Kaynak / Source: https://awsfundamentals.com/blog/cwb-video-platform</p>