McTaba Labs logo
Software EngineeringThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book Call

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
McTaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Our Work

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2027 McTaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. Paystack for African Developers
  3. Accept Payments with Paystack in Supabase Edge Functions
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Accept Payments with Paystack in Supabase Edge Functions

Create a Supabase Edge Function at supabase/functions/pay/index.ts. Store your Paystack secret key with supabase secrets set PAYSTACK_SECRET_KEY=sk_live_xxx. In the function, use Deno.env.get to read the key, call the Paystack initialize endpoint with native fetch, and return the authorization URL to your frontend.

In this article

  1. 1. Setup: Create the Edge Function
  2. 2. Initialize Transaction Function
  3. 3. Call from Frontend
  4. 4. Deploy the Function
  5. 5. Learn More

Setup: Create the Edge Function

# Create the function
supabase functions new pay

# Store the Paystack secret key
supabase secrets set PAYSTACK_SECRET_KEY=sk_live_xxxxxxxxxxxx

# For test mode
supabase secrets set PAYSTACK_SECRET_KEY=sk_test_xxxxxxxxxxxx

This creates supabase/functions/pay/index.ts.

Initialize Transaction Function

// supabase/functions/pay/index.ts
import { serve } from "https://deno.land/std@0.208.0/http/server.ts";

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};

serve(async (req) => {
  // Handle CORS preflight
  if (req.method === "OPTIONS") {
    return new Response("ok", { headers: corsHeaders });
  }

  if (req.method !== "POST") {
    return new Response("Method not allowed", { status: 405 });
  }

  try {
    const secretKey = Deno.env.get("PAYSTACK_SECRET_KEY");
    if (!secretKey) {
      return new Response(
        JSON.stringify({ error: "Paystack secret key not configured" }),
        { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
      );
    }

    const { email, amount } = await req.json();

    if (!email || !amount) {
      return new Response(
        JSON.stringify({ error: "email and amount are required" }),
        { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
      );
    }

    const reference = "edge_" + Date.now() + "_" + crypto.randomUUID().split("-")[0];

    const paystackResponse = await fetch(
      "https://api.paystack.co/transaction/initialize",
      {
        method: "POST",
        headers: {
          Authorization: "Bearer " + secretKey,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          email,
          amount: Math.round(Number(amount) * 100), // Convert to kobo
          reference,
        }),
      }
    );

    const data = await paystackResponse.json();

    if (!data.status) {
      return new Response(
        JSON.stringify({ error: data.message }),
        { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
      );
    }

    return new Response(
      JSON.stringify({
        authorization_url: data.data.authorization_url,
        access_code: data.data.access_code,
        reference: data.data.reference,
      }),
      { headers: { ...corsHeaders, "Content-Type": "application/json" } }
    );
  } catch (error) {
    return new Response(
      JSON.stringify({ error: error.message }),
      { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
    );
  }
});

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

Call from Frontend

// Using Supabase JS client
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(
  import.meta.env.VITE_SUPABASE_URL,
  import.meta.env.VITE_SUPABASE_ANON_KEY
)

async function initializePayment(email: string, amount: number) {
  const { data, error } = await supabase.functions.invoke('pay', {
    body: { email, amount }
  })

  if (error) throw error
  return data // { authorization_url, access_code, reference }
}

// Or using plain fetch:
async function initializePaymentWithFetch(email: string, amount: number) {
  var response = await fetch(
    process.env.SUPABASE_URL + '/functions/v1/pay',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + process.env.SUPABASE_ANON_KEY,
      },
      body: JSON.stringify({ email, amount }),
    }
  )
  return response.json()
}

Deploy the Function

# Deploy to production
supabase functions deploy pay

# Test locally first
supabase functions serve pay

# Test locally with curl
curl -X POST http://localhost:54321/functions/v1/pay \
  -H "Content-Type: application/json" \
  -d '{"email": "test@example.com", "amount": 5000}'

Learn More

This guide is part of the Paystack integration guides by language and framework series.

Next: Handle Paystack Webhooks in Supabase Edge Functions

Sign up for the McTaba newsletter

Key Takeaways

  • ✓Supabase Edge Functions run Deno TypeScript. They have access to native fetch, crypto, and Deno.env.
  • ✓Store your Paystack secret key with: supabase secrets set PAYSTACK_SECRET_KEY=sk_live_xxx
  • ✓Read the secret in the function with: Deno.env.get("PAYSTACK_SECRET_KEY")
  • ✓Edge Functions are deployed with: supabase functions deploy pay
  • ✓Call Edge Functions from your frontend via the Supabase JS client or directly via fetch.
  • ✓Add CORS headers to your Edge Function for browser clients (use cors module from JSR or set headers manually).

Frequently Asked Questions

Can I access the Supabase database from a Paystack Edge Function?
Yes. Use the Supabase client inside Edge Functions. Import createClient from @supabase/supabase-js. Use the service role key (SUPABASE_SERVICE_ROLE_KEY) from secrets to bypass RLS for writes after payment confirmation. Do not use the anon key for server-side database operations.
How do I set environment variables for Paystack in Supabase Edge Functions?
Use the Supabase CLI: supabase secrets set PAYSTACK_SECRET_KEY=sk_live_xxx. Read them in the function with Deno.env.get("PAYSTACK_SECRET_KEY"). Never put secrets in your function source code.
What is the Deno equivalent of Node.js process.env?
Deno.env.get("KEY_NAME"). Edge Functions run Deno, not Node.js. Use Deno.env.get() for environment variables. The syntax is slightly different but the concept is the same.
Do Supabase Edge Functions have cold start issues?
Edge Functions run at the edge (Deno Deploy), so cold starts are generally fast (under 50ms). For Paystack initialization, which is not latency-critical, this is acceptable. If cold starts become an issue, keep functions warm with scheduled pings.

Learn Paystack Integration

KES 2,999

The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.

Start Paystack Course

Not ready? Create Free Account

Keep reading

Paystack Integration Guides by Language and Framework

A complete directory of Paystack integration guides organized by programming language and framework. Each guide covers accepting payments, verifying transactions, handling webhooks, and building subscriptions in your specific stack.

Read more

Verify Paystack Payments in Supabase Edge Functions

Verify Paystack payments using Supabase Edge Functions written in Deno TypeScript. This guide covers calling the verify endpoint, validating amounts, updating your Supabase database after confirmation, and calling the function from your frontend.

Read more

Handle Paystack Webhooks in Supabase Edge Functions

Receive Paystack webhook events in a Supabase Edge Function written in Deno TypeScript. This guide covers HMAC SHA512 signature verification using the Web Crypto API, returning 200 before processing, and updating your Supabase database after confirming the event.

Read more

Build Paystack Subscriptions in Supabase Edge Functions

Add recurring billing to a Supabase project using Paystack subscriptions and Edge Functions. This guide covers creating a subscription checkout Edge Function with a plan code, handling subscription lifecycle webhooks, and querying subscription status from the database.

Read more

Why You Must Never Call the Paystack API From Your Frontend

Putting your Paystack secret key in frontend JavaScript is the most dangerous mistake in payment integration. This guide shows exactly what goes wrong, why CORS will also fight you, and the correct pattern: frontend talks to your server, your server talks to Paystack.

Read more

Paystack Transaction References: Design Patterns That Prevent Chaos

Your transaction reference is the single string that ties a Paystack payment to your internal records. A sloppy reference scheme leads to duplicate charges, mystery transactions, and 2 AM debugging sessions. This guide covers UUID, sequential, and composite patterns with code for each.

Read more

Explore related topics

M-Pesa & African Stack

M-Pesa Daraja API tutorials, USSD development, and WhatsApp Business API guides. The African Stack that global bootcamps do not teach.

Learn to Code in Kenya

Everything a Kenyan needs to know before writing their first line of code. Career paths, real costs, hardware requirements, and honest answers about what it takes.

Learning to Code

Roadmaps, language guides, and practical advice for learning to code and launching a programming career.

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

The African Stack: Skills for This Market

The skills that make Kenyan developers hard to replace: M-Pesa, USSD, WhatsApp, fintech, and building for the African market.

Bonaventure Ogeto

Bonaventure Ogeto

Founder, McTaba Labs

Bonaventure is the founder of McTaba Labs, a coding bootcamp in Nairobi, Kenya. He has spent years building products for the African market and mentoring the next generation of developers across the continent.