@moneygraph/sdk
Version:
AI-native SDK for global payouts powered by StratosPay
264 lines (224 loc) • 8.29 kB
text/typescript
/**
* MoneyGraph SDK - Supabase Edge Function Recipe
*
* Use this as a backend proxy to avoid CORS issues when calling
* the MoneyGraph SDK from browser applications.
*
* Deployment:
* 1. Create a new Edge Function: supabase functions new moneygraph
* 2. Copy this file to supabase/functions/moneygraph/index.ts
* 3. Set secret: supabase secrets set MONEYGRAPH_API_KEY=sk_test_...
* 4. Deploy: supabase functions deploy moneygraph
*
* Frontend usage:
* ```typescript
* const response = await fetch('/functions/v1/moneygraph', {
* method: 'POST',
* headers: { 'Content-Type': 'application/json' },
* body: JSON.stringify({
* action: 'payout.send',
* params: { customerId: '123', from: 'USD', to: 'NGN', amount: 100, recipient: {...} }
* }),
* });
* ```
*/
// @ts-ignore - Deno types
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
// Import types from npm (Deno can use npm: prefix)
// Note: In production, you'd bundle the SDK or use a CDN version
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
interface RequestBody {
action: string;
params: Record<string, unknown>;
}
// Simplified MoneyGraph client for Edge Function
class MoneyGraphClient {
private apiKey: string;
private baseUrl = 'https://stratospay.com/api/v1';
constructor(apiKey: string) {
this.apiKey = apiKey;
}
async request<T>(method: string, endpoint: string, body?: Record<string, unknown>): Promise<T> {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
});
const data = await response.json();
if (!response.ok || data.status === 'failed') {
throw new Error(data.message || `Request failed: ${response.status}`);
}
return data.data;
}
}
serve(async (req: Request) => {
// Handle CORS preflight
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}
try {
// @ts-ignore - Deno.env
const apiKey = Deno.env.get('MONEYGRAPH_API_KEY');
if (!apiKey) {
throw new Error('MONEYGRAPH_API_KEY not configured');
}
const client = new MoneyGraphClient(apiKey);
const { action, params } = await req.json() as RequestBody;
let result: unknown;
switch (action) {
// Customer operations
case 'customer.create':
result = await client.request('POST', '/customer/create', params);
break;
case 'customer.get':
result = await client.request('GET', `/customer/users/${params.customerId}`);
break;
case 'customer.update':
result = await client.request('POST', `/customer/update/${params.customerId}`, params.data as Record<string, unknown>);
break;
case 'customer.list':
result = await client.request('GET', '/customer/users');
break;
// KYC operations
case 'kyc.submit':
result = await client.request('POST', `/customer/submit_kyc/${params.customerId}`);
break;
case 'kyc.canPayout': {
const customer = await client.request<{ kyc_status: string }>('GET', `/customer/users/${params.customerId}`);
result = {
allowed: customer.kyc_status === 'APPROVED',
status: customer.kyc_status,
};
break;
}
// Director operations
case 'director.list':
result = await client.request('GET', `/customer/director/all/${params.customerId}`);
break;
case 'director.create':
result = await client.request('POST', `/customer/director/create/${params.customerId}`, params.data as Record<string, unknown>);
break;
case 'director.update':
result = await client.request('POST', `/customer/director/update/${params.customerId}/${params.directorId}`, params.data as Record<string, unknown>);
break;
case 'director.delete':
result = await client.request('DELETE', `/customer/director/delete/${params.customerId}/${params.directorId}`);
break;
// Wallet & Transaction operations
case 'wallet.list':
result = await client.request('GET', `/customer/wallets/${params.customerId}`);
break;
case 'transaction.list':
result = await client.request('GET', `/customer/transactions/${params.customerId}`);
break;
case 'transaction.get':
result = await client.request('GET', `/customer/transactions/${params.customerId}/${params.transactionId}`);
break;
// Quote operations (these would need real endpoints - using mock for now)
case 'quote.get':
// In production, call actual quote endpoint
result = {
id: `quote_${Date.now()}`,
from_currency: params.from,
to_currency: params.to,
from_amount: params.amount,
to_amount: (params.amount as number) * 1550, // Mock rate
rate: 1550,
fee: 2,
expires_at: new Date(Date.now() + 120000).toISOString(),
};
break;
case 'quote.confirm':
result = {
id: crypto.randomUUID(),
quote_id: params.quoteId,
status: 'confirmed',
confirmed_at: new Date().toISOString(),
};
break;
// Payout operations
case 'payout.send': {
// First check KYC
const customer = await client.request<{ kyc_status: string }>('GET', `/customer/users/${params.customerId}`);
if (customer.kyc_status !== 'APPROVED') {
throw new Error(`KYC not approved: ${customer.kyc_status}`);
}
// In production, call actual payout endpoint
result = {
id: `payout_${Date.now()}`,
status: 'pending',
created_at: new Date().toISOString(),
};
break;
}
// Reference data
case 'reference.countries':
result = await client.request('GET', '/countries');
break;
case 'reference.currencies':
result = await client.request('GET', `/currencies/${params.countryIso2}`);
break;
case 'reference.sourceOfFunds':
result = await client.request('GET', '/source_of_funds');
break;
case 'reference.mcc':
result = await client.request('GET', '/mcc');
break;
case 'reference.businessTypes':
result = await client.request('GET', '/business_registration_type');
break;
default:
throw new Error(`Unknown action: ${action}`);
}
return new Response(JSON.stringify({ success: true, data: result }), {
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
});
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
return new Response(JSON.stringify({ success: false, error: message }), {
status: 400,
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
});
}
});
/*
* Frontend Client Example:
*
* class MoneyGraphProxy {
* private baseUrl: string;
*
* constructor(supabaseUrl: string) {
* this.baseUrl = `${supabaseUrl}/functions/v1/moneygraph`;
* }
*
* private async call<T>(action: string, params: Record<string, unknown> = {}): Promise<T> {
* const response = await fetch(this.baseUrl, {
* method: 'POST',
* headers: { 'Content-Type': 'application/json' },
* body: JSON.stringify({ action, params }),
* });
* const { success, data, error } = await response.json();
* if (!success) throw new Error(error);
* return data;
* }
*
* async createCustomer(params: CreateCustomerParams) {
* return this.call('customer.create', params);
* }
*
* async getQuote(from: string, to: string, amount: number) {
* return this.call('quote.get', { from, to, amount });
* }
*
* async sendPayout(customerId: string, quoteId: string, recipient: object) {
* return this.call('payout.send', { customerId, quoteId, recipient });
* }
* }
*/