Features
Marketing API
Public subscribe and unsubscribe endpoints for email lists.
The Marketing API adds people to, and removes them from, the email lists you manage in the dashboard. Use it to power a newsletter signup form on your site; campaigns are then sent to the list from the dashboard.
These two endpoints are public: they take no API key, so you never have to expose one in a signup form.
Finding a list ID
- In the dashboard, open Marketing and select the email list.
- The list's page shows its List ID, with a button to copy it.
Only active lists accept subscribers.
Subscribe
POST /v1/marketing/subscribecurl https://api.graphcms.io/v1/marketing/subscribe \ -X POST \ -H "Content-Type: application/json" \ -d '{ "listId": "YOUR_LIST_ID", "email": "ada@example.com", "firstName": "Ada", "lastName": "Lovelace", "source": "website-footer" }'| Body property | Required | Description |
|---|---|---|
listId | yes | The list to add the subscriber to. |
email | yes | Must be a valid email address. |
firstName | no | Stored on the subscriber. |
lastName | no | Stored on the subscriber. |
source | no | Where they signed up, for your own reporting. Defaults to api. |
{ "success": true, "message": "Subscribed successfully", "subscriberId": "m4n5b6v7c8x9"}Subscribing is safe to repeat:
- An email already subscribed to the list returns
success: truewithmessage: "Already subscribed". - An email that had unsubscribed is subscribed again, with
message: "Resubscribed successfully".
| Status | Error |
|---|---|
400 | Missing required fields: listId and email |
400 | Invalid email address |
404 | Email list not found or inactive |
Unsubscribe
POST /v1/marketing/unsubscribecurl https://api.graphcms.io/v1/marketing/unsubscribe \ -X POST \ -H "Content-Type: application/json" \ -d '{ "listId": "YOUR_LIST_ID", "email": "ada@example.com" }'{ "success": true, "message": "Unsubscribed successfully" }The subscriber is kept on the list, marked as unsubscribed, so they stop receiving campaigns but can resubscribe later. Errors are 400 with Missing required fields: listId and email, and 404 with Subscriber not found.
Calling it from your site
These endpoints don't send CORS headers, so a browser on your own domain can't call api.graphcms.io directly. Send the form to your own server (an API route, a server action or a serverless function) and call Graph from there. No key is needed, so there is nothing secret to protect, only the cross-origin rule.
A Next.js route handler:
1export async function POST(request) {2 const { email, firstName } = await request.json();34 const response = await fetch('https://api.graphcms.io/v1/marketing/subscribe', {5 method: 'POST',6 headers: { 'Content-Type': 'application/json' },7 body: JSON.stringify({8 listId: process.env.GRAPH_LIST_ID,9 email,10 firstName,11 source: 'website',12 }),13 });1415 return Response.json(await response.json(), { status: response.status });16}And a form that posts to it:
1'use client';23import { useState } from 'react';45export function NewsletterForm() {6 const [status, setStatus] = useState('idle');7 const [message, setMessage] = useState('');89 async function onSubmit(event) {10 event.preventDefault();11 setStatus('loading');1213 const form = new FormData(event.currentTarget);14 const response = await fetch('/api/subscribe', {15 method: 'POST',16 headers: { 'Content-Type': 'application/json' },17 body: JSON.stringify({ email: form.get('email'), firstName: form.get('firstName') }),18 });19 const result = await response.json();2021 setStatus(result.success ? 'success' : 'error');22 setMessage(result.success ? 'Thanks! You are on the list.' : result.error);23 }2425 return (26 <form onSubmit={onSubmit}>27 <input name="firstName" placeholder="First name" />28 <input name="email" type="email" placeholder="Email" required />29 <button type="submit" disabled={status === 'loading'}>30 {status === 'loading' ? 'Subscribing…' : 'Subscribe'}31 </button>32 {message && <p role="status">{message}</p>}33 </form>34 );35}Plain HTML works the same way: point a form's fetch at your own endpoint, and have that endpoint forward the body to /v1/marketing/subscribe.