Integrating Payoneer with Lovable uses Edge Functions to onboard payees, initiate payouts, and check payment status via the Payoneer Payouts API. Store your OAuth2 client credentials in Cloud Secrets, create Edge Functions to generate access tokens and send mass payouts, then build a payout dashboard for your Lovable app. Setup takes 35 minutes.
Why integrate Payoneer with Lovable?
Payoneer solves one of the most painful problems in the global digital economy: paying freelancers, suppliers, and service providers in 190+ countries without the complexity of international wire transfers, high banking fees, and currency conversion losses. Unlike Stripe Payouts (US/EU focused) or PayPal (high fees in many countries), Payoneer specializes in cross-border business-to-business and business-to-individual payments with local bank transfer options that let recipients receive money in their home currency at favorable rates.
For Lovable developers, Payoneer integration is essential for building marketplace apps, freelance platforms, influencer payment systems, affiliate networks, and any application where your business needs to send money to people or businesses globally. Payoneer is the preferred payout method for sellers on Amazon, eBay, Fiverr, and Upwork — if your platform serves a global talent or seller base, many recipients already have Payoneer accounts and prefer it over bank wires.
The Payoneer Payouts API is the programmatic interface for sending payouts from your company's Payoneer account to registered payees. The flow involves: registering a payee (the recipient creates or links their Payoneer account via a registration link you generate), then initiating payouts from your company balance to their Payoneer account. Payoneer handles all the cross-border complexity — currency conversion, local banking relationships, and compliance.
Integration method
Payoneer has no native Lovable connector. Integration requires Supabase Edge Functions to authenticate via OAuth2 client credentials, register payees, and initiate payouts through the Payoneer Payouts API. Client ID and Secret are stored in Cloud Secrets. Access tokens are cached in Supabase to minimize authentication overhead for high-volume payout operations.
Prerequisites
- A Lovable project with Cloud enabled
- A Payoneer business account with API access enabled — contact Payoneer to request Payouts API access
- Your Payoneer API client_id and client_secret from the Payoneer Developer Dashboard
- Your Payoneer program ID (identifies your company's payout program)
- Understanding that Payoneer requires onboarding approval before API access — this can take days to weeks
Step-by-step guide
Set up Payoneer API access and store credentials
Set up Payoneer API access and store credentials
Payoneer's API access is not self-serve — you need to apply through Payoneer's business development team. Start by creating a business account at payoneer.com if you don't have one. Then contact Payoneer's API support (developer.payoneer.com has a 'Contact API Sales' link) to request Payouts API access. You'll need to provide your use case, expected payout volume, and business details. Approval typically takes 5-15 business days. Once approved, Payoneer provides access to their Developer Portal at developer.payoneer.com. Log in and create an API application under Applications → Create Application. Select 'Payouts' as the application type. You'll receive a client_id and client_secret. Also note your program_id (your company's unique payout program identifier). Payoneer has a sandbox environment at sandbox.api.payoneer.com for testing. Request sandbox access alongside production access. In your Lovable project, open Cloud tab → Secrets and add: PAYONEER_CLIENT_ID, PAYONEER_CLIENT_SECRET, PAYONEER_PROGRAM_ID, and PAYONEER_ENVIRONMENT set to 'sandbox' or 'production'. The sandbox and production environments have completely separate credentials.
Pro tip: Payoneer API access is not instant — plan for 1-2 weeks lead time in your project timeline. Request sandbox access at the same time as production access. Sandbox lets you test the full payout flow without sending real money.
Expected result: PAYONEER_CLIENT_ID, PAYONEER_CLIENT_SECRET, PAYONEER_PROGRAM_ID, and PAYONEER_ENVIRONMENT stored in Cloud Secrets. Sandbox access confirmed from Payoneer.
Create an Edge Function for Payoneer OAuth2 authentication
Create an Edge Function for Payoneer OAuth2 authentication
Payoneer uses OAuth2 client credentials flow for API authentication. Your Edge Function exchanges the client_id and client_secret for a Bearer access token, which is then used in all subsequent API calls. Access tokens expire after a set period (typically 1 hour), so you need to handle token refresh. Create supabase/functions/payoneer-auth/index.ts. The token endpoint is POST https://api.payoneer.com/v4/oauth2/token (production) or https://api.sandbox.payoneer.com/v4/oauth2/token (sandbox). The request uses Basic Auth with client_id as username and client_secret as password, with the body as application/x-www-form-urlencoded containing grant_type=client_credentials and scope=read write payouts. To avoid calling the token endpoint on every API request, cache the token in a Supabase table with the expiry timestamp. Before making an API call, check the cache — if the token is still valid (more than 5 minutes from expiry), use the cached token. Otherwise, fetch a new one and update the cache. This reduces latency and avoids hitting Payoneer's token endpoint rate limits. Create a payoneer_token_cache table in Supabase with columns: token (text), expires_at (timestamp), and environment (text).
Create a Supabase Edge Function at supabase/functions/payoneer-auth/index.ts. It should check a Supabase table called payoneer_token_cache for a valid cached token (expires_at > now + 5 minutes) for the current environment. If no valid cached token exists, call the Payoneer OAuth2 token endpoint with Basic Auth using PAYONEER_CLIENT_ID and PAYONEER_CLIENT_SECRET from Deno.env.get(), requesting scope 'read write payouts'. Store the new access_token and calculated expires_at in payoneer_token_cache. Return the access token.
Paste this in Lovable chat
1import { serve } from "https://deno.land/std@0.168.0/http/server.ts";2import { createClient } from "https://esm.sh/@supabase/supabase-js@2";34const CLIENT_ID = Deno.env.get("PAYONEER_CLIENT_ID") ?? "";5const CLIENT_SECRET = Deno.env.get("PAYONEER_CLIENT_SECRET") ?? "";6const ENVIRONMENT = Deno.env.get("PAYONEER_ENVIRONMENT") ?? "sandbox";7const SUPABASE_URL = Deno.env.get("SUPABASE_URL") ?? "";8const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "";910const TOKEN_URL = ENVIRONMENT === "production"11 ? "https://api.payoneer.com/v4/oauth2/token"12 : "https://api.sandbox.payoneer.com/v4/oauth2/token";1314const corsHeaders = {15 "Access-Control-Allow-Origin": "*",16 "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",17};1819export async function getAccessToken(): Promise<string> {20 const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY);2122 // Check cache23 const { data: cached } = await supabase24 .from("payoneer_token_cache")25 .select("token, expires_at")26 .eq("environment", ENVIRONMENT)27 .gt("expires_at", new Date(Date.now() + 5 * 60 * 1000).toISOString())28 .single();2930 if (cached?.token) return cached.token;3132 // Fetch new token33 const authString = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);34 const res = await fetch(TOKEN_URL, {35 method: "POST",36 headers: {37 "Authorization": `Basic ${authString}`,38 "Content-Type": "application/x-www-form-urlencoded",39 },40 body: "grant_type=client_credentials&scope=read+write+payouts",41 });4243 if (!res.ok) {44 const err = await res.text();45 throw new Error(`Payoneer auth failed: ${err}`);46 }4748 const data = await res.json();49 const expiresAt = new Date(Date.now() + (data.expires_in - 60) * 1000).toISOString();5051 await supabase.from("payoneer_token_cache").upsert(52 { environment: ENVIRONMENT, token: data.access_token, expires_at: expiresAt },53 { onConflict: "environment" }54 );5556 return data.access_token;57}5859serve(async (req) => {60 if (req.method === "OPTIONS") {61 return new Response("ok", { headers: corsHeaders });62 }63 try {64 const token = await getAccessToken();65 return new Response(JSON.stringify({ token }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });66 } catch (e) {67 return new Response(JSON.stringify({ error: (e as Error).message }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } });68 }69});Pro tip: Create the payoneer_token_cache table in Supabase with columns: id (uuid, default gen_random_uuid()), environment (text, unique), token (text), expires_at (timestamptz), created_at (timestamptz). Set a UNIQUE constraint on environment so the upsert works correctly.
Expected result: Edge Function returns a valid Payoneer access token. Second call within expiry window returns cached token without hitting the Payoneer token endpoint again.
Create an Edge Function to register payees
Create an Edge Function to register payees
Before you can pay someone via Payoneer, they need to be registered as a payee in your program. The registration process involves generating a unique registration link for the payee, which they click to create or connect their Payoneer account. Once registered, Payoneer returns a payee_id that you use for all future payouts to that person. Create supabase/functions/payoneer-register-payee/index.ts. This function calls the Payoneer Payees API to create a new payee record and get a registration link. The endpoint is POST https://api.payoneer.com/v4/programs/{programId}/payees (production) or the sandbox equivalent. The request body includes the payee's email, name, and an internal reference ID (your user's ID in Supabase). Payoneer returns a payee object with a registration_link the payee must visit to connect their account, and a payee_id you save in Supabase. The registration link expires after 30 days and may need to be regenerated if the payee doesn't complete onboarding. After registration, check payee status via GET /payees/{payee_id} — status 'ACTIVE' means they can receive payouts. Show a 'Connect Payoneer' button in your app that opens this registration link in a new tab.
Create a Supabase Edge Function at supabase/functions/payoneer-register-payee/index.ts. Accept POST requests with JSON body containing userId, email, firstName, and lastName. Get an access token using the getAccessToken helper. Call the Payoneer Payees API at https://api.sandbox.payoneer.com/v4/programs/{PAYONEER_PROGRAM_ID}/payees with the payee's details. Store the returned payee_id and registration_link in the Supabase users table for the given userId. Return both values to the frontend so the app can display a 'Complete Registration' button linking to the registration_link.
Paste this in Lovable chat
1import { serve } from "https://deno.land/std@0.168.0/http/server.ts";2import { createClient } from "https://esm.sh/@supabase/supabase-js@2";34const PROGRAM_ID = Deno.env.get("PAYONEER_PROGRAM_ID") ?? "";5const ENVIRONMENT = Deno.env.get("PAYONEER_ENVIRONMENT") ?? "sandbox";6const SUPABASE_URL = Deno.env.get("SUPABASE_URL") ?? "";7const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "";89const API_BASE = ENVIRONMENT === "production"10 ? "https://api.payoneer.com/v4"11 : "https://api.sandbox.payoneer.com/v4";1213const corsHeaders = {14 "Access-Control-Allow-Origin": "*",15 "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",16};1718async function getToken(): Promise<string> {19 // Import from payoneer-auth or duplicate the logic inline20 const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY);21 const { data } = await supabase.from("payoneer_token_cache").select("token").eq("environment", ENVIRONMENT).gt("expires_at", new Date().toISOString()).single();22 if (data?.token) return data.token;23 throw new Error("No valid Payoneer token — call payoneer-auth first");24}2526serve(async (req) => {27 if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders });2829 try {30 const { userId, email, firstName, lastName } = await req.json();31 const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY);32 const token = await getToken();3334 const res = await fetch(`${API_BASE}/programs/${PROGRAM_ID}/payees`, {35 method: "POST",36 headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },37 body: JSON.stringify({38 payee_id: userId,39 contact: { email, first_name: firstName, last_name: lastName },40 }),41 });4243 if (!res.ok) {44 const err = await res.text();45 throw new Error(`Payoneer payee error: ${err}`);46 }4748 const data = await res.json();49 await supabase.from("users").update({50 payoneer_payee_id: data.payee_id ?? userId,51 payoneer_registration_link: data.registration_link,52 payoneer_status: "PENDING",53 }).eq("id", userId);5455 return new Response(56 JSON.stringify({ payeeId: data.payee_id, registrationLink: data.registration_link }),57 { headers: { ...corsHeaders, "Content-Type": "application/json" } }58 );59 } catch (e) {60 return new Response(61 JSON.stringify({ error: (e as Error).message }),62 { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }63 );64 }65});Pro tip: Call the payoneer-auth Edge Function before this one to ensure a fresh token is cached. In production, consider pre-populating the token cache on a schedule rather than waiting for the first API call to fetch a token.
Expected result: Edge Function registers payees and returns registration links. Test by creating a payee with a test email — the registration link should be a valid Payoneer URL.
Create payout Edge Function and build the payout dashboard
Create payout Edge Function and build the payout dashboard
With payees registered and tokens cached, create the core payout Edge Function. This function takes a list of payout instructions (payee_id, amount, currency, description) and calls the Payoneer Payouts API to transfer money to registered payees. The Payoneer Payouts API endpoint for creating a payout is POST https://api.payoneer.com/v4/programs/{programId}/payouts (production). Each payout has a unique client_reference_id (your payout ID), a payment_type ('Payout'), amount, currency, and the destination payee_id. Payoneer processes the payout and sends webhook events when the status changes. Track each payout's status by storing the Payoneer payment_id alongside your internal payout record. Build a payout dashboard in Lovable showing pending payees, their earned balances, payout history, and a 'Run Payouts' button that triggers the batch payout function for all eligible payees. Show payout status (Pending, Processing, Paid, Failed) in real-time using Supabase realtime subscriptions. For failed payouts, show the failure reason and provide a retry button. For complex payout scenarios with split payments, foreign currency handling, or compliance holds, RapidDev's team can help implement the full payout workflow.
Create a payout management dashboard. Show a table of payees with their Payoneer status (from Supabase users table), pending balance, and last payout date. Add a 'Run Payouts' button that calls a payoneer-send-payout Edge Function for all users with status ACTIVE and pending_balance > 10. The Edge Function should call the Payoneer Payouts API for each eligible user, store the returned payment_id in a payouts table, and mark the payout as sent. Display payout history with status badges using Supabase realtime to update statuses when webhook events arrive.
Paste this in Lovable chat
1import { serve } from "https://deno.land/std@0.168.0/http/server.ts";2import { createClient } from "https://esm.sh/@supabase/supabase-js@2";34const PROGRAM_ID = Deno.env.get("PAYONEER_PROGRAM_ID") ?? "";5const ENVIRONMENT = Deno.env.get("PAYONEER_ENVIRONMENT") ?? "sandbox";6const SUPABASE_URL = Deno.env.get("SUPABASE_URL") ?? "";7const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "";89const API_BASE = ENVIRONMENT === "production"10 ? "https://api.payoneer.com/v4"11 : "https://api.sandbox.payoneer.com/v4";1213const corsHeaders = {14 "Access-Control-Allow-Origin": "*",15 "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",16};1718serve(async (req) => {19 if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders });2021 try {22 const { payouts } = await req.json() as { payouts: Array<{ payeeId: string; amount: number; currency: string; description: string; internalId: string }> };23 const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY);2425 // Get cached token26 const { data: tokenData } = await supabase.from("payoneer_token_cache").select("token").eq("environment", ENVIRONMENT).gt("expires_at", new Date().toISOString()).single();27 if (!tokenData?.token) throw new Error("No valid token — refresh authentication");2829 const results: Array<{ internalId: string; success: boolean; paymentId?: string; error?: string }> = [];3031 for (const payout of payouts) {32 const res = await fetch(`${API_BASE}/programs/${PROGRAM_ID}/payouts`, {33 method: "POST",34 headers: { "Authorization": `Bearer ${tokenData.token}`, "Content-Type": "application/json" },35 body: JSON.stringify({36 client_reference_id: payout.internalId,37 payee_id: payout.payeeId,38 amount: payout.amount,39 currency: payout.currency,40 description: payout.description,41 }),42 });4344 const data = await res.json();45 if (res.ok && data.payment_id) {46 await supabase.from("payouts").update({ payoneer_payment_id: data.payment_id, status: "sent" }).eq("id", payout.internalId);47 results.push({ internalId: payout.internalId, success: true, paymentId: data.payment_id });48 } else {49 await supabase.from("payouts").update({ status: "failed", error_message: data.message ?? "Unknown error" }).eq("id", payout.internalId);50 results.push({ internalId: payout.internalId, success: false, error: data.message });51 }52 }5354 return new Response(JSON.stringify({ results }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });55 } catch (e) {56 return new Response(JSON.stringify({ error: (e as Error).message }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } });57 }58});Pro tip: Process payouts one at a time with individual error handling rather than sending them all in one API call. This way, a single failed payout doesn't block all the others. Store each result immediately so the dashboard shows accurate status even if the function times out mid-run.
Expected result: Payout Edge Function processes payouts and updates Supabase with Payoneer payment IDs. Dashboard shows real-time payout status. Test payouts appear in the Payoneer sandbox portal.
Common use cases
Marketplace seller payouts for completed orders
A freelance services marketplace pays sellers weekly for completed and delivered orders. When an order is marked complete, the Edge Function records the payout amount owed. On the weekly payout schedule, a batch payout Edge Function sends all pending payments to registered Payoneer payees in their local currencies. Sellers in India, the Philippines, and Eastern Europe receive money in their local currency via local bank transfer.
Build a weekly marketplace payout system. Create a Supabase table to track pending payouts with sellerId, amount, currency, and orderId. Create an Edge Function that runs on a weekly schedule (or triggered manually from admin dashboard) to fetch all pending payouts from Supabase, group them by Payoneer payee ID, and call the Payoneer Payouts API to send each payment. On success, mark the payout as sent with the Payoneer payment ID. On failure, mark as failed with the error reason. Show a payout history page for sellers in their dashboard.
Copy this prompt to try it in Lovable
Affiliate commission payments
An affiliate marketing platform tracks referral commissions and pays affiliates monthly. Affiliates register their Payoneer account via an onboarding link generated by the Edge Function. At month end, the Edge Function calculates each affiliate's earned commissions from the Supabase database and initiates payouts to their registered Payoneer accounts. Commission payments above the minimum threshold ($20) are sent automatically.
Create an affiliate payout system. Add a 'Connect Payoneer' button to the affiliate dashboard. When clicked, call an Edge Function that generates a Payoneer payee registration link for the affiliate (using the Create Payee API with the affiliate's email and name). Store the payeeId returned by Payoneer in the affiliate's Supabase profile. Create a monthly payout Edge Function that queries affiliates with unpaid commissions over $20, initiates Payoneer payouts to each, and records the payment IDs in a commissions_paid table.
Copy this prompt to try it in Lovable
Creator economy tip and revenue sharing
A creator platform distributes ad revenue and tip income to creators globally. Each creator connects their Payoneer account during onboarding. The platform holds accumulated earnings in the company Payoneer account and sends payouts on a rolling 30-day basis. Creators in regions without robust Stripe support (parts of Southeast Asia, Africa, Middle East) receive reliable payouts through Payoneer's local bank transfer network.
Build creator revenue distribution using Payoneer. During creator signup, generate a Payoneer payee registration URL via an Edge Function and embed it as a mandatory onboarding step. Once connected, save their Payoneer payeeId to Supabase. Create an Edge Function that runs monthly to fetch all creators with balance over $10 (from a creator_earnings table), initiate Payoneer payouts for each, and log the payout in a creator_payouts table with amount, payoneer_payment_id, and status. Update creator balance to zero after confirmed payouts.
Copy this prompt to try it in Lovable
Troubleshooting
OAuth2 token request returns 401 or 'invalid_client' error
Cause: The PAYONEER_CLIENT_ID and PAYONEER_CLIENT_SECRET combination is wrong, the application credentials haven't been activated yet, or you're using sandbox credentials against the production endpoint.
Solution: Verify your credentials in the Payoneer Developer Portal. Confirm PAYONEER_ENVIRONMENT in Cloud Secrets matches the credentials (sandbox vs production). Sandbox credentials only work with sandbox.api.payoneer.com. If credentials are newly created, they may need a few minutes to activate in Payoneer's system after creation.
Payee registration returns 400 or 'payee already exists'
Cause: The payee_id (your internal user ID used as Payoneer payee reference) already exists in your Payoneer program, or the email is already registered to another payee in the program.
Solution: Check if the user already has a payoneer_payee_id in your Supabase users table before calling the registration endpoint. If they do, use GET /payees/{payee_id} to retrieve their current registration link instead of creating a new one. Payoneer allows regenerating registration links for existing payees that haven't completed onboarding.
1// Check for existing payee before creating:2const { data: user } = await supabase.from('users').select('payoneer_payee_id').eq('id', userId).single();3if (user?.payoneer_payee_id) {4 // Fetch existing registration link instead of creating new payee5 const existing = await fetch(`${API_BASE}/programs/${PROGRAM_ID}/payees/${user.payoneer_payee_id}`, ...);6}Payout API returns 'payee not active' or 'payee status pending'
Cause: The payee was registered (payee record created) but has not yet completed their Payoneer account registration via the registration link. Payouts can only be sent to ACTIVE payees who have completed KYC.
Solution: Check the payee's status via GET /programs/{programId}/payees/{payeeId}. Status 'PENDING' means they haven't clicked the registration link. Status 'ACTIVE' means they're ready for payouts. Send a reminder email with the registration link stored in your Supabase users table. Registration links expire after 30 days — generate a new one if expired.
Payout processing fails with 'insufficient funds' error
Cause: Your Payoneer business account balance is insufficient to cover the payout amount. Payoneer payouts debit from your company's Payoneer balance, which must be funded before sending payouts.
Solution: In the Payoneer Business Portal, check your account balance. Fund your Payoneer account via bank transfer or wire transfer before running payouts. Implement a balance check in your payout Edge Function by calling the Payoneer Balances API before initiating payouts to avoid failed batches mid-run.
Best practices
- Store PAYONEER_CLIENT_ID and PAYONEER_CLIENT_SECRET in Cloud Secrets and never expose them in frontend code — all API calls must go through Edge Functions
- Cache OAuth2 access tokens in Supabase to minimize API calls to the token endpoint — generate a new token only when the cached one is within 5 minutes of expiry
- Always save Payoneer payment IDs to your Supabase payouts table immediately after a successful payout API call — you need these IDs for status checks, dispute resolution, and reconciliation
- Implement idempotency by checking if a payout with the same client_reference_id already exists in Payoneer before creating a new one — this prevents duplicate payouts if your Edge Function is called twice
- Build payee status checks into your payout workflow — only attempt payouts to ACTIVE payees, and surface a clear 'Complete Payoneer setup' prompt to PENDING payees in their dashboard
- Run payouts in small batches (20-50 per batch) with individual error handling rather than sending hundreds in a single function call — this prevents timeouts and ensures partial success in case of individual failures
- Monitor your Payoneer company account balance before scheduled payout runs and send automated alerts when the balance drops below your typical weekly payout volume
Alternatives
Stripe Connect handles payouts to service providers with better US/EU coverage and developer experience; Payoneer is preferred for global payouts in countries where Stripe has limited payout support.
PayPal Payouts offers broad global coverage with instant transfers to PayPal accounts; Payoneer is preferred for recipients who want local bank transfers rather than holding a PayPal balance.
Adyen provides enterprise global payment processing with unified POS and online payments, while Payoneer specializes in cross-border mass payouts to freelancers and contractors.
Frequently asked questions
How long does it take for Payoneer payouts to reach recipients?
Payoneer payout timing depends on the recipient's payout method. Payoneer-to-Payoneer transfers are typically instant. Payoneer to local bank account takes 2-5 business days depending on the country and bank. Payoneer to prepaid card is typically same-day. Processing times are outside your control once the payout is initiated via API — you can only check status. Build user expectations around the slowest option (5 business days) to avoid support issues.
Does Payoneer require KYC verification for payees?
Yes — Payoneer requires all payees to complete identity verification (KYC) as part of their account registration. This is handled within Payoneer's registration flow that the payee completes after clicking the registration link you generate. Until KYC is complete, the payee status remains PENDING and payouts will be blocked. KYC requirements vary by country but typically require government-issued ID.
What countries does Payoneer support for payouts?
Payoneer supports payouts to recipients in 190+ countries. However, local bank transfer availability varies by country — some countries support direct bank deposits while others require recipients to keep funds in their Payoneer balance or withdraw via other methods. Check the Payoneer website for country-specific transfer options. Payoneer's coverage in Southeast Asia, South Asia, Latin America, and Eastern Europe is particularly strong relative to Stripe.
Can I send payouts in multiple currencies?
Yes — Payoneer supports payouts in 70+ currencies. Specify the currency code in the payout API request. Payoneer handles the currency conversion from your account's balance currency. Note that currency conversion involves Payoneer's exchange rate, which includes a spread above the mid-market rate. For large payout programs, negotiate currency terms with your Payoneer account manager.
How do I handle failed payouts and notify recipients?
Monitor Payoneer webhook events for payout status changes. Failed payouts return a status of 'FAILED' with an error code in the webhook payload. Store the failure reason in your Supabase payouts table and send the recipient an email explaining the issue (account details incorrect, account suspended, etc.). Implement a retry mechanism in your dashboard that lets admins resubmit failed payouts after the root cause is resolved.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation