penna
Integrations

Create Subscriber

Learn how to add new subscribers to your project programmatically.

Create Subscriber

Penna provides a simple REST API to integrate newsletter functionality directly into your application. This guide will show you how to authenticate and add subscribers programmatically.

Authentication

All API requests must be authenticated using your project's Public Key. You can find this key in your project settings dashboard.

Include the key in the x-penna-public-key header of your requests.

x-penna-public-key: penn_your_public_key_here

[!WARNING] Your Public Key is exposed to anyone who visits your website. While it creates a seamless integration, we recommend proxying these requests through your own backend API if you want to control rate limits or add additional spam protection layers before calling Penna.

Endpoints

Add New Subscriber

Adds a new subscriber to your project.

Endpoint: POST /api/v1/external/projects/subscriber/new

Headers:

  • Content-Type: application/json
  • x-penna-public-key: <YOUR_PUBLIC_KEY>

Body:

{
  "email": "user@example.com"
}

Code Examples

Here is how you can integrate the "Subscribe" functionality in various languages.

React / Next.js

components/newsletter-form.tsx
import { useState } from "react";

export function NewsletterForm() {
  const [email, setEmail] = useState("");
  const [status, setStatus] = useState("idle");

  const subscribe = async (e) => {
    e.preventDefault();
    setStatus("loading");

    try {
      const res = await fetch(
        "https://api.penna.dev/api/v1/external/projects/subscriber/new",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            "x-penna-public-key": "penn_abc1234567890", // Replace with your public key
          },
          body: JSON.stringify({ email }),
        }
      );

      if (!res.ok) throw new Error("Failed to subscribe");

      setStatus("success");
      setEmail("");
    } catch (err) {
      setStatus("error");
    }
  };

  return (
    <form onSubmit={subscribe} className="flex gap-2">
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Enter your email"
        required
        className="border p-2 rounded"
      />
      <button
        type="submit"
        disabled={status === "loading"}
        className="bg-black text-white p-2 rounded"
      >
        {status === "loading" ? "Subscribing..." : "Subscribe"}
      </button>
      {status === "success" && <p className="text-green-500">Subscribed!</p>}
      {status === "error" && (
        <p className="text-red-500">Something went wrong.</p>
      )}
    </form>
  );
}

HTML / JavaScript (Vanilla)

index.html
<form id="newsletter-form">
  <input type="email" id="email" placeholder="your@email.com" required />
  <button type="submit">Join Newsletter</button>
</form>

<script>
  const form = document.getElementById("newsletter-form");

  form.addEventListener("submit", async (e) => {
    e.preventDefault();
    const email = document.getElementById("email").value;

    try {
      const response = await fetch(
        "https://api.penna.dev/api/v1/external/projects/subscriber/new",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            "x-penna-public-key": "penn_abc1234567890",
          },
          body: JSON.stringify({ email }),
        }
      );

      if (response.ok) {
        alert("Successfully subscribed!");
      } else {
        alert("Subscription failed.");
      }
    } catch (error) {
      console.error("Error:", error);
    }
  });
</script>

cURL

curl -X POST https://api.penna.dev/api/v1/external/projects/subscriber/new \
  -H "Content-Type: application/json" \
  -H "x-penna-public-key: penn_abc1234567890" \
  -d '{"email": "test@example.com"}'

Python (Requests)

import requests

url = "https://api.penna.dev/api/v1/external/projects/subscriber/new"
headers = {
    "Content-Type": "application/json",
    "x-penna-public-key": "penn_abc1234567890"
}
data = {
    "email": "test@example.com"
}

response = requests.post(url, json=data, headers=headers)

if response.status_code == 200:
    print("Subscribed successfully!")
else:
    print(f"Failed: {response.text}")