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/jsonx-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
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)
<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}")