Skills Plugins MCP Prompt Model 博客 我的中心
开发编程 #api #web

convex-http-actions

External API integration and webhook handling including HTTP endpoint routing, request/response handling, authentication, CORS configuration, and webhook signature validation

DeepseekModel 官方收录技能 质量 优秀 · 78 v1.0.0

获取

https://deepseekmodel.com/api/download.php?id=waynesutton-convexskills-skills-convex-http-actions-skill-md&format=skill
下载 .skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用
.skill 文件中 system_prompt 字段的实际内容。
name convex-http-actions displayName Convex HTTP Actions description External API integration and webhook handling including HTTP endpoint routing, request/response handling, authentication, CORS configuration, and webhook signature validation version 1.0.0 author Convex tags ["convex","http","actions","webhooks","api","endpoints"] Convex HTTP Actions Build HTTP endpoints for webhooks, external API integrations, and custom routes in Convex applications. Documentation Sources Before implementing, do not assume; fetch the latest documentation: Primary: https://docs.convex.dev/functions/http-actions Actions Overview: https://docs.convex.dev/functions/actions Authentication: https://docs.convex.dev/auth For broader context: https://docs.convex.dev/llms.txt Instructions HTTP Actions Overview HTTP actions allow you to define HTTP endpoints in Convex that can: Receive webhooks from third-party services Create custom API routes Handle file uploads Integrate with external services Serve dynamic content Basic HTTP Router Setup // convex/http.ts import { httpRouter } from "convex/server" ; import { httpAction } from "./_generated/server" ; const http = httpRouter (); // Simple GET endpoint http. route ({ path : "/health" , method : "GET" , handler : httpAction ( async (ctx, request) => { return new Response ( JSON . stringify ({ status : "ok" }), { status : 200 , headers : { "Content-Type" : "application/json" }, }); }), }); export default http; Request Handling // convex/http.ts import { httpRouter } from "convex/server" ; import { httpAction } from "./_generated/server" ; const http = httpRouter (); // Handle JSON body http. route ({ path : "/api/data" , method : "POST" , handler : httpAction ( async (ctx, request) => { // Parse JSON body const body = await request. json (); // Access headers const authHeader = request. headers . get ( "Authorization" ); // Access URL parameters const url = new URL (request. url ); const queryParam = url. searchParams . get ( "filter" ); return new Response ( JSON . stringify ({ received : body, filter : queryParam }), { status : 200 , headers : { "Content-Type" : "application/json" }, } ); }), }); // Handle form data http. route ({ path : "/api/form" , method : "POST" , handler : httpAction ( async (ctx, request) => { const formData = await request. formData (); const name = formData. get ( "name" ); const email = formData. get ( "email" ); return new Response ( JSON . stringify ({ name, email }), { status : 200 , headers : { "Content-Type" : "application/json" }, } ); }), }); // Handle raw bytes http. route ({ path : "/api/upload" , method : "POST" , handler : httpAction ( async (ctx, request) => { const bytes = await request. bytes (); const contentType = request. headers . get ( "Content-Type" ) ?? "application/octet-stream" ; // Store in Convex storage const blob = new Blob ([bytes], { type : contentType }); const storageId = await ctx. storage . store (blob); return new Response ( JSON . stringify ({ storageId }), { status : 200 , headers : { "Content-Type" : "application/json" }, } ); }), }); export default http; Path Parameters Use path prefix matching for dynamic routes: // convex/http.ts import { httpRouter } from "convex/server" ; import { httpAction } from "./_generated/server" ; const http = httpRouter (); // Match /api/users/* with pathPrefix http. route ({ pathPrefix : "/api/users/" , method : "GET" , handler : httpAction ( async (ctx, request) => { const url = new URL (request. url ); // Extract user ID from path: /api/users/123 -> "123" const userId = url. pathname . replace ( "/api/users/" , "" ); return new Response ( JSON . stringify ({ userId }), { status : 200 , headers : { "Content-Type" : "application/json" }, } ); }), }); export default http; CORS Configuration // convex/http.ts import { httpRouter } from "convex/server" ; import { httpAction } from "./_generated/server" ; const http = httpRouter (); // CORS headers helper const corsHeaders = { "Access-Control-Allow-Origin" : "*" , "Access-Control-Allow-Methods" : "GET, POST, PUT, DELETE, OPTIONS" , "Access-Control-Allow-Headers" : "Content-Type, Authorization" , "Access-Control-Max-Age" : "86400" , }; // Handle preflight requests http. route ({ path : "/api/data" , method : "OPTIONS" , handler : httpAction ( async () => { return new Response ( null , { status : 204 , headers : corsHeaders, }); }), }); // Actual endpoint with CORS http. route ({ path : "/api/data" , method : "POST" , handler : httpAction ( async (ctx, request) => { const body = await request. json (); return new Response ( JSON . stringify ({ success : true , data : body }), { status : 200 , headers : { "Content-Type" : "application/json" , ...corsHeaders, }, } ); }), }); export default http; Webhook Handling // convex/http.ts import { httpRouter } from "convex/server" ; import { httpAction } from "./_generated/server" ; import { internal } from "./_generated/api" ; const http = httpRouter (); // Stripe webhook http. route ({ path : "/webhooks/stripe" , method : "POST" , handler : httpAction ( async (ctx, request) => { const signature = request. headers . get ( "stripe-signature" ); if (!signature) { return new Response ( "Missing signature" , { status : 400 }); } const body = await request. text (); // Verify webhook signature (in action with Node.js) try { await ctx. runAction (internal. stripe . verifyAndProcessWebhook , { body, signature, }); return new Response ( "OK" , { status : 200 }); } catch (error) { console . error ( "Webhook error:" , error); return new Response ( "Webhook error" , { status : 400 }); } }), }); // GitHub webhook http. route ({ path : "/webhooks/github" , method : "POST" , handler : httpAction ( async (ctx, request) => { const event = request. headers . get ( "X-GitHub-Event" ); const signature = request. headers . get ( "X-Hub-Signature-256" ); if (!signature) { return new Response ( "Missing signature" , { status : 400 }); } const body = await request. text (); await ctx. runAction (internal. github . processWebhook , { event : event ?? "unknown" , body, signature, }); return new Response ( "OK" , { status : 200 }); }), }); export default http; Webhook Signature Verification // convex/stripe.ts "use node" ; import { internalAction, internalMutation } from "./_generated/server" ; import { internal } from "./_generated/api" ; import { v } from "convex/values" ; import Stripe from "stripe" ; const stripe = new Stripe (process. env . STRIPE_SECRET_KEY !); export const verifyAndProcessWebhook = internalAction ({ args : { body : v. string (), signature : v. string (), }, returns : v. null (), handler : async (ctx, args) => { const webhookSecret = process. env . STRIPE_WEBHOOK_SECRET !; // Verify signature const event = stripe. webhooks . constructEvent ( args. body , args. signature , webhookSecret ); // Process based on event type switch (event. type ) { case "checkout.session.completed" : await ctx. runMutation (internal. payments . handleCheckoutComplete , { sessionId : event. data . object . id , customerId : event. data . object . customer as string , }); break ; case "customer.subscription.updated" : await ctx. runMutation (internal. subscriptions . handleUpdate , { subscriptionId : event. data . object . id , status : event. data . object . status , }); break ; } return null ; }, }); Authentication in HTTP Actions // convex/http.ts import { httpRouter } from "convex/server" ; import { httpAction } from "./_generated/server" ; import { internal } from "./_generated/api" ; const http = httpRouter (); // API key authentication http. route ({ path : "/api/protected" , method : "GET" , handler : httpAction ( async (ctx, request) => { const apiKey = request. headers . get ( "X-API-Key" ); if (!apiKey) { return new Response ( JSON . stringify ({ error : "Missing API key" }), { status : 401 , headers : { "Content-Type" : "application/json" } } ); } // Validate API key const isValid = await ctx. runQuery (internal. auth . validateApiKey , { apiKey, }); if (!isValid) { return new Response ( JSON . stringify ({ error : "Invalid API key" }), { status : 403 , headers : { "Content-Type" : "application/json" } } ); } // Process authenticated request const data = await ctx. runQuery (internal. data . getProtectedData , {}); return new Response ( JSON . stringify (data), { status : 200 , headers : { "Content-Type" : "application/json" } } ); }), }); // Bearer token authentication http. route ({ path : "/api/user" , method : "GET" , handler : httpAction ( async (ctx, request) => { const authHeader = request. headers . get ( "Authorization" ); if (!authHeader?. startsWith ( "Bearer " )) { return new Response ( JSON . stringify ({ error : "Missing or invalid Authorization header" }), { status : 401 , headers : { "Content-Type" : "application/json" } } ); } const token = authHeader. slice ( 7 ); // Validate token and get user const user = await ctx. runQuery (internal. auth . validateToken , { token }); if (!user) { return new Response ( JSON . stringify ({ error : "Invalid token" }), { status : 403 , headers : { "Content-Type" : "application/json" } } ); } return new Response ( JSON . stringify (user), { status : 200 , headers : { "Content-Type" : "application/json" } } ); }), }); export default http; Calling Mutations and Queries // convex/http.ts import { httpRouter } from "convex/server" ; import { httpAction } from "./_generated/server" ; import { api, internal } from "./_generated/api" ; const http = httpRouter (); http. route ({ path : "/api/items" , method : "POST" , handler : httpAction ( async (ctx, request) => { const body = await request. json (); // Call a mutation const itemId = await ctx. runMutation (internal. items . create , { name : body. name , description : body. description , }); // Query the created item
Agent 识别该技能的关键词,点击任意一个即可复制。

该技能未提供触发词。

下载的 .skill 包内含以下字段。
字段 说明
format格式标识(skill/v1)
skill_id技能唯一 ID
name技能名称
version版本号
description技能描述
category所属分类(数组)
trigger_words触发词列表
tags标签列表
source来源标识
source_url来源链接(本页地址)
exported_at导出时间(每次下载生成)
system_prompt系统提示词正文
model_config模型参数:provider / model / temperature / max_tokens / top_p
examples示例
install_guide各平台导入说明(Coze / Dify / Claude / 自定义框架)
同一份技能可按不同平台格式导出。
.skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用 下载
.skillpro 增强格式,额外含脚本 / 工具 / 依赖 / 钩子占位 下载
.json 纯 JSON 导出,只含 system_prompt 与模型参数 下载
Coze 带 frontmatter 的 Markdown,Coze 平台导入用 下载
Dify Dify DSL,创建应用后直接导入 下载

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。