Skip to main content
notification-image-iphone

Overview

When a user enables notifications for your Mini App, the Base App generates a unique notification token and url which is sent to your server via webhook. This token grants your app permission to send push notifications to that specific user. To send a notification, make a POST request to the url with the user’s notification token and your content. You will receive webhook events when users enable or disable notifications for your app. When disabled, the notification token becomes invalid and should no longer be used.

Implementation

1

Create a webhook server

Create a webhook server to handle webhook events.
app/api/webhook/route.ts
export async function POST(request: NextRequest) {
  const requestJson = await request.json();

  // Parse and verify the webhook event
  let data;
  try {
    data = await validateWebhookEventSignature(requestJson);
    // Events are signed by the app key of a user with a JSON Farcaster Signature.
  } catch (e: unknown) {
    // Handle verification errors (invalid data, invalid app key, etc.)
    // Return appropriate error responses with status codes 400, 401, or 500
  }

  const fid = data.fid;
  const event = data.event;

  // Handle different event types
  switch (event.event) {
    case "miniapp_added":
      // Save notification details and send welcome notification
      if (event.notificationDetails) {
        await setUserNotificationDetails(fid, event.notificationDetails);
        await sendMiniAppNotification({
          fid,
          title: "Welcome to Base Mini Apps",
          body: "Mini app is now added to your client",
        });
      }
      break;

    case "miniapp_removed":
      // Delete notification details
      await deleteUserNotificationDetails(fid);
      break;

    case "notifications_enabled":
      // Save new notification details and send confirmation
      await setUserNotificationDetails(fid, event.notificationDetails);
      await sendMiniAppNotification({
        fid,
        title: "Ding ding ding",
        body: "Notifications are now enabled",
      });
      break;

    case "notifications_disabled":
      // Delete notification details
      await deleteUserNotificationDetails(fid);
      break;
  }

  return Response.json({ success: true });
}
2

Add the Webhook URL to your manifest

Add the Webhook URL to your manifest file
app/.well-known/farcaster.json
{
  "accountAssociation": {
    "header": "eyJmaWQiOjU0NDgsInR5cGUiOiJjdXN0b2R5Iiwia2V5IjoiMHg2MWQwMEFENzYwNjhGOEQ0NzQwYzM1OEM4QzAzYUFFYjUxMGI1OTBEIn0",
    "payload": "eyJkb21haW4iOiJleGFtcGxlLmNvbSJ9",
    "signature": "MHg3NmRkOWVlMjE4OGEyMjliNzExZjUzOTkxYTc1NmEzMGZjNTA3NmE5OTU5OWJmOWFmYjYyMzAyZWQxMWQ2MWFmNTExYzlhYWVjNjQ3OWMzODcyMTI5MzA2YmJhYjdhMTE0MmRhMjA4MmNjNTM5MTJiY2MyMDRhMWFjZTY2NjE5OTFj"
  },
  "miniapp": {
    "version": "1",
    "name": "Example App",
    "iconUrl": "https://example.com/icon.png",
    "homeUrl": "https://example.com",
    "imageUrl": "https://example.com/image.png",
    "buttonTitle": "Check this out",
    "splashImageUrl": "https://example.com/splash.png",
    "splashBackgroundColor": "#eeccff",
    "webhookUrl": "https://example.com/api/webhook"
  }
}

3

Prompt users to add your Mini App

Use the addMiniApp() hook to prompt users to add your Mini App
page.tsx
"use client";

import { sdk } from "@farcaster/miniapp-sdk";
import { useCallback, useState } from "react";

export default function AddMiniApp() {
  const [result, setResult] = useState("");

  const handleAddMiniApp = useCallback(async () => {
    try {
      const response = await sdk.actions.addMiniApp();
      
      if (response.notificationDetails) {
        setResult("Mini App added with notifications enabled!");
      } else {
        setResult("Mini App added without notifications");
      }
    } catch (error) {
      setResult(`Error: ${error}`);
    }
  }, []);

  return (
    <div>
      <button onClick={handleAddMiniApp}>
        Add Mini App
      </button>
      {result && <p>{result}</p>}
    </div>
  );
}
4

Save the token and URL from the webhook event

The token and url need to be securely saved to a database so they can be looked up when you want to send a notification to a particular user.
miniapp_added_payload.json
{
  "event": "notifications_enabled",
  "notificationDetails": {
    "url": "https://api.farcaster.xyz/v1/frame-notifications",
    "token": "a05059ef2415c67b08ecceb539201cbc6"
  }
}
5

Send notifications

Send notifications by sending a POST request to the url associated with the user’s token
sendNotification.ts
export async function sendMiniAppNotification({
  fid,
  title,
  body,
}: {
  fid: number;
  title: string;
  body: string;
}): Promise<sendMiniAppNotificationResult> {
  const notificationDetails = await getUserNotificationDetails(fid);
  if (!notificationDetails) {
    return { state: "no_token" };
  }

  const response = await fetch(notificationDetails.url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      notificationId: crypto.randomUUID(),
      title,
      body,
      targetUrl: appUrl,
      tokens: [notificationDetails.token],
    } satisfies SendNotificationRequest),
  });

  const responseJson = await response.json();

  if (response.status === 200) {
    const responseBody = sendNotificationResponseSchema.safeParse(responseJson);
    if (responseBody.success === false) {
      // Malformed response
      return { state: "error", error: responseBody.error.errors };
    }

    if (responseBody.data.result.rateLimitedTokens.length) {
      // Rate limited
      return { state: "rate_limit" };
    }

    return { state: "success" };
  } else {
    // Error response
    return { state: "error", error: responseJson };
  }
}

Schema

Send Notification Request Schema

notificationId
string
required
Identifier that is combined with the FID to form an idempotency key. When the user opens the Mini App from the notification this ID will be included in the context object. Maximum length of 128 characters.
title
string
required
Title of the notification. Max length 32 characters.
body
string
required
Body of the notification. Max length 128 characters.
targetUrl
string
required
URL to open when the user clicks the notification. Max length 1024 characters. Must be on the same domain as the Mini App.
tokens
string[]
required
Array of notification tokens to send to. Max 100 tokens.

Send Notification Response Schema

successfulTokens
string[]
required
Tokens for which the notification succeeded.
invalidTokens
string[]
required
Tokens which are no longer valid and should never be used again. This could happen if the user disabled notifications but for some reason the Mini App server has no record of it.
rateLimitedTokens
string[]
required
Tokens for which the rate limit was exceeded. The Mini App server can try later.

Events

Mini App events use the following object structure:
  • type: notification event type
  • notificationDetails.url: URL that the app should call to send a notification.
  • notificationDetails.token: A secret token generated by the Base App and shared with the Notification Server. A token is unique for each (Farcaster Client, Mini App, user Fid) tuple.
If users are not seeing the option to enable notifications when they call addMiniApp(), verify that your manifest file contains a valid webhookUrl.

miniapp_added

Sent when the user adds the Mini App to their Farcaster client (whether or not it was triggered by an addMiniApp() prompt).
miniapp_added_payload.json
{
  "event": "miniapp_added",
  "notificationDetails": {
    "url": "https://api.farcaster.xyz/v1/frame-notifications",
    "token": "a05059ef2415c67b08ecceb539201cbc6"
  }
}

miniapp_removed

Sent when a user removes the Mini App, which means that any notification tokens for that FID and client app (based on signer requester) should be considered invalid:
miniapp_removed_payload
{
  "event": "miniapp_removed"
}

notifications_enabled

Sent when a user enables notifications (e.g. after disabling them). The payload includes a new token and url:
notifications_enabled_payload
{
  "event": "notifications_enabled",
  "notificationDetails": {
    "url": "https://api.farcaster.xyz/v1/frame-notifications",
    "token": "a05059ef2415c67b08ecceb539201cbc6"
  }
}

notifications_disabled

Sent when a user disables notifications from, e.g., a settings panel in the client app. Any notification tokens for that FID and client app (based on signer requester) should be considered invalid:
notifications_disabled_json
{
  "event": "notifications_disabled"
}
I