Last active
June 8, 2024 13:44
-
-
Save borispoehland/2738d2edd62e83f332260a80eb5a9335 to your computer and use it in GitHub Desktop.
Vercel Webhook to call to pause the project after the spending limit is reached
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import crypto from 'crypto' | |
const { INTEGRATION_SECRET, VERCEL_TEAM_ID, VERCEL_TOKEN } = process.env | |
function sha1(data: Buffer, secret: string): string { | |
return crypto.createHmac('sha1', secret).update(data).digest('hex') | |
} | |
export async function POST(request: Request) { | |
if (typeof INTEGRATION_SECRET != 'string') { | |
throw new Error('No integration secret found') | |
} | |
const rawBody = await request.text() | |
const rawBodyBuffer = Buffer.from(rawBody, 'utf-8') | |
const bodySignature = sha1(rawBodyBuffer, INTEGRATION_SECRET) | |
if (bodySignature !== request.headers.get('x-vercel-signature')) { | |
return Response.json({ | |
code: 'invalid_signature', | |
error: "signature didn't match", | |
}) | |
} | |
const { projects } = (await fetch( | |
`https://api.vercel.com/v9/projects?teamId=${VERCEL_TEAM_ID}`, | |
{ | |
headers: { | |
Authorization: `Bearer ${VERCEL_TOKEN}`, | |
}, | |
} | |
).then((res) => res.json())) as { projects: { id: string }[] } | |
let isSuccess = true | |
for (const project of projects) { | |
const pauseProject = await fetch( | |
`https://api.vercel.com/v1/projects/${project.id}/pause?teamId=${VERCEL_TEAM_ID}`, | |
{ | |
headers: { | |
Authorization: `Bearer ${VERCEL_TOKEN}`, | |
}, | |
method: 'POST', | |
} | |
) | |
if (!pauseProject.ok) { | |
// send me a backup notification to my email | |
console.error(pauseProject.statusText) | |
isSuccess = false | |
} | |
} | |
return Response.json({ code: 'paused_all', data: isSuccess }) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// /api/project/pause/route.ts | |
import crypto from 'crypto' | |
const { INTEGRATION_SECRET, VERCEL_PROJECT_ID, VERCEL_TEAM_ID, VERCEL_TOKEN } = | |
process.env | |
function sha1(data: Buffer, secret: string): string { | |
return crypto.createHmac('sha1', secret).update(data).digest('hex') | |
} | |
export async function POST(request: Request) { | |
if (typeof INTEGRATION_SECRET != 'string') { | |
throw new Error('No integration secret found') | |
} | |
const rawBody = await request.text() | |
const rawBodyBuffer = Buffer.from(rawBody, 'utf-8') | |
const bodySignature = sha1(rawBodyBuffer, INTEGRATION_SECRET) | |
if (bodySignature !== request.headers.get('x-vercel-signature')) { | |
return Response.json({ | |
code: 'invalid_signature', | |
error: "signature didn't match", | |
}) | |
} | |
const pauseProject = await fetch( | |
`https://api.vercel.com/v1/projects/${VERCEL_PROJECT_ID}/pause?teamId=${VERCEL_TEAM_ID}`, | |
{ | |
headers: { | |
Authorization: `Bearer ${VERCEL_TOKEN}`, | |
'Content-Type': 'application/json', | |
}, | |
method: 'POST', | |
} | |
) | |
if (!pauseProject.ok) { | |
// send me a backup notification to my email | |
console.error(pauseProject.statusText) | |
} | |
return Response.json({ code: 'paused', data: pauseProject.ok }) | |
} |
Nice, thanks! Used this to write a small repo that can be directly deployed separately on Vercel.
Do we still need to manually pause/resume projects or is it automatically handled now??
I'm told its automatic now by some YouTuber.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you! Do you know if there is any "easy" way to test it works?