// /api/minikit/notifications
import { NextRequest, NextResponse } from 'next/server';

const FARCASTER_API_URL = 'https://api.farcaster.xyz';
const MAX_NOTIFICATIONS_PER_HOUR = 10;

interface NotificationRequest {
  title: string;
  body: string;
  targetFid?: string;
  actionUrl?: string;
}

export async function POST(request: NextRequest) {
  try {
    const { title, body, targetFid, actionUrl }: NotificationRequest = await request.json();
    
    // Validate request
    if (!title || !body) {
      return NextResponse.json(
        { error: 'Title and body are required' },
        { status: 400 }
      );
    }
    
    if (title.length > 100 || body.length > 500) {
      return NextResponse.json(
        { error: 'Title or body too long' },
        { status: 400 }
      );
    }
    
    // Check rate limits (implement your own rate limiting logic)
    const isRateLimited = await checkRateLimit(request);
    if (isRateLimited) {
      return NextResponse.json(
        { error: 'Rate limit exceeded' },
        { status: 429 }
      );
    }
    
    // Forward to Farcaster notification API
    const response = await fetch(`${FARCASTER_API_URL}/notifications`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.FARCASTER_API_KEY}`,
      },
      body: JSON.stringify({
        title,
        body,
        targetFid,
        actionUrl: actionUrl || process.env.MINI_APP_URL,
        appId: process.env.MINI_APP_ID,
      }),
    });
    
    if (!response.ok) {
      throw new Error(`Notification API error: ${response.status}`);
    }
    
    const result = await response.json();
    return NextResponse.json(result);
    
  } catch (error) {
    console.error('Notification error:', error);
    return NextResponse.json(
      { error: 'Failed to send notification' },
      { status: 500 }
    );
  }
}

async function checkRateLimit(request: NextRequest): Promise<boolean> {
  // Implement your rate limiting logic here
  // Consider using Redis or a database to track notification counts
  // Return true if rate limit is exceeded
  return false;
}
Defined in @coinbase/onchainkit
Notifications are not yet available in Base App but are coming soon. This documentation describes the upcoming API that will be available when notifications are fully deployed.
ebcbglkhecg
Allows Mini Apps to send push notifications to users who have saved your app. Notifications require a backend proxy route to handle the actual delivery and enforce rate limiting.

Parameters

options
NotificationOptions
required
Configuration object for the notification to send.

Required Backend Setup

Notifications require a backend proxy route to handle delivery and rate limiting:
// /api/minikit/notifications
import { NextRequest, NextResponse } from 'next/server';

const FARCASTER_API_URL = 'https://api.farcaster.xyz';
const MAX_NOTIFICATIONS_PER_HOUR = 10;

interface NotificationRequest {
  title: string;
  body: string;
  targetFid?: string;
  actionUrl?: string;
}

export async function POST(request: NextRequest) {
  try {
    const { title, body, targetFid, actionUrl }: NotificationRequest = await request.json();
    
    // Validate request
    if (!title || !body) {
      return NextResponse.json(
        { error: 'Title and body are required' },
        { status: 400 }
      );
    }
    
    if (title.length > 100 || body.length > 500) {
      return NextResponse.json(
        { error: 'Title or body too long' },
        { status: 400 }
      );
    }
    
    // Check rate limits (implement your own rate limiting logic)
    const isRateLimited = await checkRateLimit(request);
    if (isRateLimited) {
      return NextResponse.json(
        { error: 'Rate limit exceeded' },
        { status: 429 }
      );
    }
    
    // Forward to Farcaster notification API
    const response = await fetch(`${FARCASTER_API_URL}/notifications`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.FARCASTER_API_KEY}`,
      },
      body: JSON.stringify({
        title,
        body,
        targetFid,
        actionUrl: actionUrl || process.env.MINI_APP_URL,
        appId: process.env.MINI_APP_ID,
      }),
    });
    
    if (!response.ok) {
      throw new Error(`Notification API error: ${response.status}`);
    }
    
    const result = await response.json();
    return NextResponse.json(result);
    
  } catch (error) {
    console.error('Notification error:', error);
    return NextResponse.json(
      { error: 'Failed to send notification' },
      { status: 500 }
    );
  }
}

async function checkRateLimit(request: NextRequest): Promise<boolean> {
  // Implement your rate limiting logic here
  // Consider using Redis or a database to track notification counts
  // Return true if rate limit is exceeded
  return false;
}

Frontend Usage

import { useNotification } from '@coinbase/onchainkit/minikit';
import { useState } from 'react';

export default function GameCompletion({ playerStats }) {
  const [isNotifying, setIsNotifying] = useState(false);
  const sendNotification = useNotification();

  const notifyAchievement = async () => {
    setIsNotifying(true);
    
    try {
      await sendNotification({
        title: "🎮 New Achievement Unlocked!",
        body: `You just beat ${playerStats.level} with a score of ${playerStats.score}! Can your friends do better?`,
        actionUrl: `${window.location.origin}/challenge/${playerStats.gameId}`
      });
      
      console.log('Achievement notification sent!');
    } catch (error) {
      console.error('Failed to send notification:', error);
    } finally {
      setIsNotifying(false);
    }
  };

  return (
    <div className="game-completion">
      <h2>🏆 Level Complete!</h2>
      <p>Score: {playerStats.score}</p>
      
      <button 
        onClick={notifyAchievement}
        disabled={isNotifying}
        className="notify-btn"
      >
        {isNotifying ? 'Sending...' : 'Share Achievement'}
      </button>
    </div>
  );
}

Rate Limiting Guidelines

  • Per user: Maximum 10 notifications per hour
  • Per app: Maximum 1000 notifications per hour
  • Burst protection: Maximum 3 notifications per minute

Implementation Strategy

lib/rate-limit.ts
// Redis-based rate limiting example
import Redis from 'ioredis';

const redis = new Redis(process.env.REDIS_URL);

async function checkRateLimit(appId: string, userFid?: string): Promise<boolean> {
  const now = Date.now();
  const hourKey = `notifications:${appId}:${Math.floor(now / 3600000)}`;
  
  // Check app-wide limits
  const appCount = await redis.incr(hourKey);
  await redis.expire(hourKey, 3600);
  
  if (appCount > 1000) {
    return true; // Rate limited
  }
  
  // Check per-user limits if targeting specific user
  if (userFid) {
    const userKey = `notifications:${appId}:user:${userFid}:${Math.floor(now / 3600000)}`;
    const userCount = await redis.incr(userKey);
    await redis.expire(userKey, 3600);
    
    if (userCount > 10) {
      return true; // Rate limited
    }
  }
  
  return false; // Not rate limited
}

Best Practices

Content Guidelines

  • Be relevant: Only send notifications related to user activity or time-sensitive events
  • Personalize: Use user-specific information when available
  • Clear value: Ensure each notification provides clear value to the recipient
  • Timing: Send notifications at appropriate times (avoid late night/early morning)

Technical Considerations

  • Error handling: Always handle notification failures gracefully
  • Retry logic: Implement exponential backoff for failed deliveries
  • Analytics: Track notification delivery rates and user engagement
  • Privacy: Respect user notification preferences and provide opt-out mechanisms

User Experience

  • Frequency control: Allow users to control notification frequency
  • Category filters: Let users choose types of notifications they want
  • Action relevance: Ensure notification action URLs are contextually relevant
Excessive or irrelevant notifications may lead to users removing your Mini App. Always prioritize user experience over engagement metrics.
When implemented thoughtfully, notifications can significantly increase user engagement and retention for your Mini App. Focus on providing genuine value with each notification sent.