Skip to main content

Overview

IntegrationPurposeWhere used
SolanaSOL payments, Phantom/AppKit, transaction verificationlib/solana.ts, lib/solana-client.ts, PaymentForm, /api/payment, /api/execute
DodoCard/UPI checkout, webhooks, confirm-payment/api/dodo/create-checkout, /api/dodo/webhook, /api/dodo/confirm-payment
GitHubOAuth, create repo, push project files/api/github/authorize, /api/github/callback, /api/github/upload
OpenRouterAI (Idea, Intent, Platform, Execute)lib/openai.ts
Details: Integrations.

1. Solana Integration

Flow

  • Client: Get agentAddress (Treasury) from GET /api/payment/config
  • Client: Call POST /api/payment with sessionId, selectedPlatform, userWalletPubKey → server runs validatePayment; on success, client builds and signs the transaction
  • Client: createPaymentTransaction(from, to, amount) from lib/solana-client (SPL or SOL fallback), sign via AppKit/Phantom, connection.confirmTransaction(signature, 'confirmed')
  • Client: Call POST /api/execute with { sessionId, transactionSignature } → server runs verifyTransaction then executes

Client: build and send payment (React)

import { PublicKey } from '@solana/web3.js';
import { createPaymentTransaction } from '@/lib/solana-client';

async function handlePayment(publicKey, connection, walletProvider, amount, onSuccess, onError) {
  const configRes = await fetch('/api/payment/config');
  const { agentAddress } = await configRes.json();
  const toPubkey = new PublicKey(agentAddress);

  const tx = await createPaymentTransaction(publicKey, toPubkey, amount);

  const { blockhash } = await connection.getLatestBlockhash();
  tx.recentBlockhash = blockhash;
  tx.feePayer = publicKey;

  const solanaProvider = walletProvider;
  const signature = typeof solanaProvider.signAndSendTransaction === 'function'
    ? await solanaProvider.signAndSendTransaction(tx)
    : (await connection.sendRawTransaction(
        (await solanaProvider.signTransaction(tx)).serialize()
      ));

  await connection.confirmTransaction(signature, 'confirmed');
  onSuccess(signature, publicKey.toString());
}

Server: validate and verify (lib/solana.ts)

// validatePayment: before user sends tx
const result = await validatePayment(userWalletPubKey, requiredAmount);
// { valid, balance, required, message? }

// verifyTransaction: after user pays
const ok = await verifyTransaction(transactionSignature);
// true if status.err === null && confirmationStatus present

createPaymentTransaction (SPL vs SOL)

  • SPL: USE_SPL_TOKEN=true and mint set → createTransferInstruction from user ATA to treasury ATA
  • SOL fallback: SystemProgram.transfer with lamports derived from amount
See Solana Integration.

2. Dodo Payments Integration

Flow

  • Create checkout: POST /api/dodo/create-checkout → get checkout_url
  • Redirect: user pays on Dodo
  • Webhook: Dodo POST to /api/dodo/webhook; handler verifies signature and updates Workflow
  • Optional: call POST /api/dodo/confirm-payment if webhook is delayed
  • Execute: POST /api/execute with { sessionId }

Client: create checkout and redirect

const res = await fetch('/api/dodo/create-checkout', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ sessionId: '...', platform: 'Web Application' }),
});
const data = await res.json();
if (data.status === 'success' && data.checkout_url) {
  window.location.href = data.checkout_url;
}

Server: create checkout

const payload = {
  product_cart: [{ product_id: productId, quantity: 1 }],
  return_url: `${process.env.NEXT_PUBLIC_APP_URL}/payment/success?sessionId=${sessionId}&platform=${platform}`,
  metadata: { session_id: sessionId, platform },
  customization: { redirect_immediately: true },
};

const response = await fetch('https://live.dodopayments.com/checkouts', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.DODO_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(payload),
});
const data = await response.json();

Webhook: signature verification

import crypto from 'crypto';

function verifyWebhookSignature(rawBody, signature, secret) {
  if (!signature || Array.isArray(signature)) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

Confirm-payment (fallback)

  • POST /api/dodo/confirm-payment
  • Updates Workflow: paymentMethod, paymentId, currentStage, selectedPlatform
See Dodo Payments.

3. GitHub Integration

Flow

  • Authorize: GET /api/github/authorize?sessionId=...
  • Callback: GET /api/github/callback?code=...&state=...
  • Upload: POST /api/github/upload → create repo and push files

OAuth: authorize

const state = Buffer.from(JSON.stringify({ sessionId })).toString('base64');
res.setHeader('Set-Cookie', `github_oauth_state=${state}; HttpOnly; SameSite=Lax; Path=/; Max-Age=600`);
const authUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${callbackUrl}&scope=repo&state=${state}`;
return res.redirect(authUrl);

OAuth: callback

  • Verify state
  • Exchange code for token
  • Fetch user
  • Set cookies
  • Redirect to Execution

Upload: create repo and push files

const accessToken = req.cookies.github_access_token;

const createRes = await fetch('https://api.github.com/user/repos', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Accept': 'application/vnd.github.v3+json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: projectName, description, private: isPrivate }),
});

Client: start OAuth

const statusRes = await fetch('/api/github/status');
const { connected } = await statusRes.json();
if (!connected) {
  window.location.href = `/api/github/authorize?sessionId=${sessionId}`;
}

4. OpenRouter Integration

Where it’s used

  • Idea: processIdea
  • Intent: refineIntent
  • Platform: selectPlatform
  • Execute: executeX402Workflow

callOpenRouter

import { callOpenRouter } from '@/lib/openai';

const text = await callOpenRouter('Explain async/await in JavaScript.', 'GROK', {
  temperature: 0.7,
  systemPrompt: 'You are a concise teacher.',
});

createChatCompletion (internal)

const response = await fetch(process.env.OPENROUTER_BASE_URL, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${modelConfig.apiKey}`,
    'HTTP-Referer': process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000',
    'X-Title': 'Scriptonia Platform',
  },
  body: JSON.stringify({
    model: modelConfig.model,
    messages: [
      { role: 'system', content: '...' },
      { role: 'user', content: '...' },
    ],
    temperature: 0.7,
    response_format: { type: 'json_object' },
  }),
});

Model and key mapping

ModelEnv keyModel ID (env override)
GROKOPENROUTER_API_KEY_GROK4GROK4_MODEL
QWENOPENROUTER_API_KEY_QWEN3QWEN3_MODEL
GEMINIOPENROUTER_API_KEY_GEMINI2_5GEMINI2_5_MODEL
DEFAULT_MODEL is used by Idea, Intent, Platform; Execution often uses GROK explicitly.