Back to Docs

Best Practices

Guidelines for building secure, performant, and maintainable integrations with Yeld.

Security Best Practices

Protect Your Master Mnemonic

Your master mnemonic is the key to all your business wallets. Store it securely and never expose it to the client.

// ✅ Good: Store in environment variable
EVM_MASTER_MNEMONIC=your_secure_mnemonic

// ❌ Bad: Hardcoding in source
const mnemonic = "your mnemonic here";

Use Environment Variables

Store all secrets in environment variables. Never commit .env files to version control.

// .env.local (add to .gitignore)
EVM_MASTER_MNEMONIC=...
SUPABASE_SERVICE_ROLE_KEY=...

// .gitignore
.env.local
.env.production

Validate All Inputs

Always validate user inputs on the server side. Don't trust client-side validation alone.

// Server action with validation
"use server";

export async function createCheckoutLink(bizId: string, input: Input) {
  // Validate business ownership
  const user = await getCurrentUser();
  if (!user) throw new Error("Unauthorized");
  
  const business = await getBusiness(bizId);
  if (!business || business.ownerId !== user.id) {
    throw new Error("Not authorized");
  }
  
  // Validate price
  const price = Number(input.price);
  if (Number.isNaN(price) || price <= 0) {
    throw new Error("Invalid price");
  }
  // ... rest of logic
}

Verify Webhook Signatures

Always verify webhook signatures to ensure requests are authentic.

import { createHmac } from "crypto";

function verifySignature(payload: string, signature: string): boolean {
  const expected = createHmac("sha256", process.env.YELD_WEBHOOK_SECRET!)
    .update(payload)
    .digest("hex");
  
  return signature === expected;
}

Performance Optimization

Use Server Components

Leverage Next.js server components to reduce client-side JavaScript bundle size.

// Server component (default in App Router)
export default async function DashboardPage({ params }) {
  const business = await getBusiness(params.bizId);
  const wallet = await getOrCreateBusinessWallet(business.id);
  
  return <Dashboard business={business} wallet={wallet} />;
}

Implement Caching

Use Next.js caching for frequently accessed data that doesn't change often.

import { unstable_cache } from "next/cache";

export const getRealtimePrices = unstable_cache(
  fetchRealtimePrices,
  ["crypto-usd-prices"],
  { revalidate: 30 } // Revalidate every 30 seconds
);

Optimize Database Queries

Use proper indexes and avoid N+1 query problems.

// ✅ Good: Single query with joins
const results = await db
  .select()
  .from(checkoutLinks)
  .where(eq(checkoutLinks.businessId, businessId))
  .orderBy(desc(checkoutLinks.createdAt));

// ❌ Bad: Multiple queries in loop
for (const link of links) {
  const sessions = await db
    .select()
    .from(checkoutSessions)
    .where(eq(checkoutSessions.checkoutLinkId, link.id));
}

User Experience Best Practices

Provide Clear Feedback

Show loading states, success messages, and clear error messages to users.

// Show loading and error states
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);

<Button onClick={handleAction} disabled={loading}>
  {loading ? "Processing..." : "Submit"}
</Button>

{error && (
  <p className="text-sm text-destructive">{error}</p>
)}

Handle Errors Gracefully

Catch errors and provide helpful error messages. Don't expose internal details to users.

try {
  await createCheckoutLink(bizId, input);
} catch (error) {
  // Log error internally
  console.error("Failed to create link:", error);
  
  // Show user-friendly message
  setError("Failed to create checkout link. Please try again.");
}

Make Actions Reversible

Allow users to undo actions when possible, or provide clear confirmation dialogs.

// Confirmation dialog for destructive actions
<ConfirmDialog
  onConfirm={() => deleteCheckoutLink(bizId, planId)}
  confirmationText="This action cannot be undone."
/>

Integration Best Practices

Use Type Safety

Leverage TypeScript for type-safe integrations. Define interfaces for your data models.

// Define types for your integration
interface CheckoutLink {
  planId: string;
  planName: string;
  price: number;
  billing: "recurring" | "one-time";
  createdAt: Date;
}

// Use typed API responses
async function getLinks(bizId: string): Promise<CheckoutLink[]> {
  const response = await fetch(...);
  return response.json() as Promise<CheckoutLink[]>;
}

Implement Idempotency

Make your webhook handlers idempotent to handle duplicate events safely.

// Check if event was already processed
async function handleWebhook(event: WebhookEvent) {
  // Check if we've already processed this event
  const existing = await db
    .select()
    .from(processedEvents)
    .where(eq(processedEvents.eventId, event.id))
    .limit(1);
  
  if (existing.length > 0) {
    return; // Already processed
  }
  
  // Process event
  await processEvent(event);
  
  // Mark as processed
  await db.insert(processedEvents).values({ eventId: event.id });
}

Test Thoroughly

Test your integration thoroughly before going to production. Use testnets and sandbox environments.

// Test file example
describe("Checkout Links", () => {
  it("should create a checkout link", async () => {
    const result = await createCheckoutLink("test-biz-id", {
      planName: "Test Plan",
      price: "10.00",
      billing: "one-time",
    });
    
    expect(result.ok).toBe(true);
  });
  
  it("should reject invalid prices", async () => {
    const result = await createCheckoutLink("test-biz-id", {
      planName: "Test Plan",
      price: "-1.00",
      billing: "one-time",
    });
    
    expect(result.ok).toBe(false);
  });
});

Additional Tips

  • Monitor Your Dashboard

    Regularly check your dashboard for unusual activity or errors.

  • Keep Dependencies Updated

    Regularly update your dependencies to get security patches and new features.

  • Document Your Integration

    Keep documentation of your integration for future reference and team members.

  • Plan for Scaling

    Design your integration to handle increased traffic and transactions as your business grows.