agentsclimarketplace

Canva deploy integration

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/canva-pack/skills/canva-deploy-integration

425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill canva-deploy-integration

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

'Deploy Canva Connect API integrations to Vercel, Fly.io, and Cloud Run.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

5.2 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it

Canva Deploy Integration

Overview

Deploy Canva Connect API integrations to popular platforms with secure OAuth credential management. The Canva API requires server-side token exchange — client secrets and refresh tokens must never reach the browser.

Prerequisites

  • Canva OAuth credentials (client ID + secret)
  • Platform CLI installed (vercel, fly, or gcloud)
  • HTTPS domain for OAuth redirect URIs
  • Application code ready for deployment

Vercel

Secrets

# Add Canva OAuth credentials
vercel env add CANVA_CLIENT_ID production
vercel env add CANVA_CLIENT_SECRET production
vercel env add CANVA_REDIRECT_URI production  # e.g. https://your-app.vercel.app/auth/canva/callback

vercel.json

{
  "functions": {
    "api/**/*.ts": {
      "maxDuration": 30
    }
  },
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "no-store" }
      ]
    }
  ]
}

API Route (Next.js / Vercel Functions)

// api/canva/callback.ts — OAuth callback
export async function GET(req: Request) {
  const url = new URL(req.url);
  const code = url.searchParams.get('code');
  const state = url.searchParams.get('state');

  // Exchange code for tokens (server-side only)
  const tokens = await exchangeCodeForToken({
    code: code!,
    codeVerifier: await getVerifierFromSession(state!),
    clientId: process.env.CANVA_CLIENT_ID!,
    clientSecret: process.env.CANVA_CLIENT_SECRET!,
    redirectUri: process.env.CANVA_REDIRECT_URI!,
  });

  // Store tokens in your database
  await saveTokens(userId, tokens);
  return Response.redirect('/dashboard');
}

Fly.io

fly.toml

app = "my-canva-app"
primary_region = "iad"

[env]
  NODE_ENV = "production"
  CANVA_REDIRECT_URI = "https://my-canva-app.fly.dev/auth/canva/callback"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true

Secrets

fly secrets set CANVA_CLIENT_ID=OCAxxxxxxxxxxxxxxxx
fly secrets set CANVA_CLIENT_SECRET=xxxxxxxxxxxxxxxx
fly deploy

Google Cloud Run

Deploy Script

#!/bin/bash
PROJECT_ID="${GOOGLE_CLOUD_PROJECT}"
SERVICE_NAME="canva-integration"
REGION="us-central1"

# Store secrets in Secret Manager
echo -n "OCAxxxxxxxxxxxxxxxx" | gcloud secrets create canva-client-id --data-file=-
echo -n "xxxxxxxxxxxxxxxx" | gcloud secrets create canva-client-secret --data-file=-

# Build and deploy
gcloud builds submit --tag gcr.io/$PROJECT_ID/$SERVICE_NAME

gcloud run deploy $SERVICE_NAME \
  --image gcr.io/$PROJECT_ID/$SERVICE_NAME \
  --region $REGION \
  --platform managed \
  --allow-unauthenticated \
  --set-secrets="CANVA_CLIENT_ID=canva-client-id:latest,CANVA_CLIENT_SECRET=canva-client-secret:latest" \
  --set-env-vars="CANVA_REDIRECT_URI=https://$SERVICE_NAME-xxxxx.run.app/auth/canva/callback"

Health Check

// api/health.ts — confirms Canva API connectivity
export async function GET() {
  const start = Date.now();
  let canvaStatus: string;

  try {
    const res = await fetch('https://api.canva.com/rest/v1/users/me', {
      headers: { 'Authorization': `Bearer ${await getServiceToken()}` },
      signal: AbortSignal.timeout(5000),
    });
    canvaStatus = res.ok ? 'healthy' : `error:${res.status}`;
  } catch {
    canvaStatus = 'unreachable';
  }

  return Response.json({
    status: canvaStatus === 'healthy' ? 'healthy' : 'degraded',
    services: { canva: { status: canvaStatus, latencyMs: Date.now() - start } },
    timestamp: new Date().toISOString(),
  });
}

Redirect URI Configuration

After deploying, update your Canva integration settings with the production redirect URI:

PlatformRedirect URI Pattern
Vercelhttps://your-app.vercel.app/auth/canva/callback
Fly.iohttps://your-app.fly.dev/auth/canva/callback
Cloud Runhttps://your-service-xxxxx.run.app/auth/canva/callback
Custom Domainhttps://app.yourdomain.com/auth/canva/callback

Error Handling

IssueCauseSolution
OAuth callback failsRedirect URI mismatchUpdate URI in Canva dashboard
Secret not foundMissing env varAdd via platform CLI
Cold start timeoutOAuth exchange slowSet min instances to 1
HTTPS requiredHTTP redirect URIAll platforms default to HTTPS

Resources

Next Steps

For webhook handling, see canva-webhooks-events.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.