Integrations #
Connect the Nellie API with popular platforms and services.
Overview #
The Nellie API can be integrated with various platforms to automate book generation workflows. This guide covers common integration patterns and platform-specific instructions.
Zapier #
Connect Nellie to 5,000+ apps without code.
Setting Up a Zap #
- Create a new Zap in Zapier
- Choose your trigger (e.g., “New row in Google Sheets”)
- Add a Webhooks by Zapier action
- Action Event: POST
- URL:
https://api.nelliewriter.com/v1/book - Headers:
X-API-Key: nel_your_api_key
Content-Type: application/json
- Data (JSON):
{
"prompt": "{{trigger_data}}",
"style": "automatic",
"type": "novel",
"output_format": "pdf",
"webhook_url": "https://hooks.zapier.com/hooks/catch/YOUR_WEBHOOK"
}
Receiving Results #
- Create another Zap with trigger: Webhooks by Zapier → Catch Hook
- Copy the webhook URL and use it as your
webhook_url - Add actions to handle the completed book (save to Dropbox, email, etc.)
Example: Google Sheets → Nellie → Email #
Trigger: New row in Google Sheets
↓
Action: Webhooks POST to Nellie API
↓
(Wait for webhook callback)
↓
Action: Send email with download link
Make (Integromat) #
Visual automation with advanced logic.
HTTP Module Setup #
- Add an HTTP > Make a request module
- Configure:
- URL:
https://api.nelliewriter.com/v1/book - Method: POST
- Headers:
X-API-Key: Your API keyContent-Type:application/json- Body type: Raw
- Content type: JSON
- Request content:
{
"prompt": "{{1.prompt}}",
"style": "{{1.style}}",
"output_format": "pdf"
}
Webhook Receiver #
- Add a Webhooks > Custom webhook module as a trigger
- Copy the webhook address
- Use it as your
webhook_urlin API requests
Example Scenario #
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Google Form │───▶│ Nellie API │───▶│ Webhook │
│ submission │ │ POST /book │ │ receiver │
└─────────────────┘ └─────────────────┘ └────────┬────────┘
│
┌─────────────────┐ ┌───────────▼────────┐
│ Email result │◀───│ Download file │
│ to customer │ │ from resultUrl │
└─────────────────┘ └────────────────────┘
n8n #
Self-hosted workflow automation.
HTTP Request Node #
{
"nodes": [
{
"name": "Nellie API",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://api.nelliewriter.com/v1/book",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"options": {},
"headerParametersUi": {
"parameter": [
{
"name": "X-API-Key",
"value": "={{ $credentials.apiKey }}"
}
]
},
"bodyParametersJson": {
"prompt": "={{ $json.prompt }}",
"style": "automatic",
"output_format": "pdf",
"webhook_url": "https://your-n8n-instance.com/webhook/nellie"
}
}
}
]
}
Webhook Trigger #
- Add a Webhook node as trigger
- Set path to
/webhook/nellie - Use the full URL as your
webhook_url
AWS Lambda #
Serverless book generation.
Lambda Function (Python) #
import json
import os
import boto3
from nellie_api import Nellie
def handler(event, context):
client = Nellie(api_key=os.environ['NELLIE_API_KEY'])
# Parse input
body = json.loads(event.get('body', '{}'))
prompt = body.get('prompt', 'A thriller story')
# Start generation
book = client.books.create(
prompt=prompt,
style=body.get('style', 'automatic'),
output_format='pdf',
webhook_url=os.environ['WEBHOOK_URL']
)
return {
'statusCode': 202,
'body': json.dumps({
'requestId': book.request_id,
'message': 'Generation started'
})
}
Webhook Handler Lambda #
import json
import boto3
from nellie_api import Webhook, WebhookSignatureError
s3 = boto3.client('s3')
ses = boto3.client('ses')
def handler(event, context):
# Verify signature
body = event.get('body', '')
sig_header = event['headers'].get('x-nellie-signature', '')
try:
book = Webhook.construct_event(
body, sig_header, os.environ['WEBHOOK_SECRET']
)
except WebhookSignatureError:
return {'statusCode': 400, 'body': 'Invalid signature'}
if book.is_successful():
# Download and store in S3
import requests
response = requests.get(book.result_url)
s3.put_object(
Bucket='my-books-bucket',
Key=f'books/{book.request_id}.pdf',
Body=response.content
)
# Send notification email
ses.send_email(
Source='noreply@example.com',
Destination={'ToAddresses': ['user@example.com']},
Message={
'Subject': {'Data': 'Your book is ready!'},
'Body': {'Text': {'Data': f'Download: {book.result_url}'}}
}
)
return {'statusCode': 200, 'body': 'OK'}
SAM Template #
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Runtime: python3.11
Environment:
Variables:
NELLIE_API_KEY: !Ref NellieApiKey
WEBHOOK_SECRET: !Ref WebhookSecret
Resources:
GenerateBookFunction:
Type: AWS::Serverless::Function
Properties:
Handler: generate.handler
Events:
Api:
Type: Api
Properties:
Path: /generate
Method: POST
WebhookFunction:
Type: AWS::Serverless::Function
Properties:
Handler: webhook.handler
Events:
Api:
Type: Api
Properties:
Path: /webhook/nellie
Method: POST
Policies:
- S3CrudPolicy:
BucketName: !Ref StoriesBucket
- SESCrudPolicy:
IdentityName: '*'
Google Cloud Functions #
Function Code #
import functions_framework
from flask import jsonify
from nellie_api import Nellie, Webhook, WebhookSignatureError
import os
@functions_framework.http
def generate_book(request):
""Start a book generation.""
client = Nellie(api_key=os.environ['NELLIE_API_KEY'])
data = request.get_json(silent=True) or {}
book = client.books.create(
prompt=data.get('prompt', 'A random book'),
style=data.get('style', 'automatic'),
webhook_url=os.environ['WEBHOOK_URL']
)
return jsonify({
'requestId': book.request_id,
'status': book.status
}), 202
@functions_framework.http
def webhook_handler(request):
""Handle Nellie webhook callbacks.""
try:
book = Webhook.construct_event(
request.data,
request.headers.get('X-Nellie-Signature'),
os.environ['WEBHOOK_SECRET']
)
except WebhookSignatureError:
return 'Invalid signature', 400
if book.is_successful():
# Store result in Firestore
from google.cloud import firestore
db = firestore.Client()
db.collection('books').document(book.request_id).set({
'status': 'completed',
'result_url': book.result_url,
'credits_used': book.credits_used
})
return 'OK', 200
Airtable #
Use Airtable’s scripting extension with the API.
Script Example #
// Airtable Script - Generate Book from Record
const API_KEY = 'nel_your_api_key';
const API_URL = 'https://api.nelliewriter.com/v1/book';
// Get selected record
let table = base.getTable('Stories');
let record = await input.recordAsync('Select a record', table);
if (record) {
let prompt = record.getCellValue('Prompt');
let style = record.getCellValue('Style') || 'automatic';
// Call Nellie API
let response = await remoteFetchAsync(API_URL, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: prompt,
style: style,
output_format: 'pdf'
})
});
let result = await response.json();
// Update record with request ID
await table.updateRecordAsync(record.id, {
'Request ID': result.requestId,
'Status': 'Processing'
});
output.text(`Started generation: ${result.requestId}`);
}
Slack Integration #
Send book notifications to Slack.
Webhook Handler with Slack #
import requests
from flask import Flask, request
from nellie_api import Webhook, WebhookSignatureError
import os
app = Flask(__name__)
SLACK_WEBHOOK_URL = os.environ['SLACK_WEBHOOK_URL']
WEBHOOK_SECRET = os.environ['NELLIE_WEBHOOK_SECRET']
@app.route('/webhooks/nellie', methods=['POST'])
def nellie_webhook():
try:
book = Webhook.construct_event(
request.data,
request.headers.get('X-Nellie-Signature'),
WEBHOOK_SECRET
)
except WebhookSignatureError:
return 'Invalid signature', 400
# Send to Slack
if book.is_successful():
slack_message = {
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"✅ *Book Generated!*n`{book.request_id}`"
}
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": f"*Credits:* {book.credits_used}"},
{"type": "mrkdwn", "text": f"*Status:* Completed"}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "Download"},
"url": book.result_url
}
]
}
]
}
else:
slack_message = {
"text": f"❌ Book generation failed: {book.error}"
}
requests.post(SLACK_WEBHOOK_URL, json=slack_message)
return 'OK', 200
Discord Integration #
Post results to a Discord channel.
import requests
from nellie_api import Webhook, WebhookSignatureError
DISCORD_WEBHOOK_URL = os.environ['DISCORD_WEBHOOK_URL']
def send_to_discord(book):
if book.is_successful():
embed = {
"title": "📚 Book Generated!",
"color": 0x00ff00,
"fields": [
{"name": "Request ID", "value": f"`{book.request_id}`", "inline": True},
{"name": "Credits", "value": str(book.credits_used), "inline": True},
],
"description": f"[Download your book]({book.result_url})"
}
else:
embed = {
"title": "❌ Generation Failed",
"color": 0xff0000,
"description": book.error
}
requests.post(DISCORD_WEBHOOK_URL, json={"embeds": })
Notion Integration #
Store generated stories in Notion.
from notion_client import Client
from nellie_api import Webhook
notion = Client(auth=os.environ['NOTION_TOKEN'])
DATABASE_ID = os.environ['NOTION_DATABASE_ID']
def save_to_notion(book):
notion.pages.create(
parent={"database_id": DATABASE_ID},
properties={
"Title": {"title": [{"text": {"content": f"Book {book.request_id[:8]}"}}]},
"Status": {"select": {"name": book.status.capitalize()}},
"Credits Used": {"number": book.credits_used},
"Request ID": {"rich_text": [{"text": {"content": book.request_id}}]},
"Download URL": {"url": book.result_url if book.is_successful() else None},
"Created": {"date": {"start": book.created_at}}
}
)
Best Practices #
API Key Security #
- Use environment variables — Never hardcode keys
- Rotate keys regularly — Especially if exposed
- Limit scope — Use different keys for different integrations
- Always verify signatures — Prevent unauthorized access
- Respond quickly — Return 200 within 30 seconds
- Process asynchronously — Queue heavy work
- Handle retries — Be idempotent
- Implement retries — For transient failures
- Log everything — For debugging
- Alert on failures — Set up monitoring
Webhook Reliability #
Error Handling #
Related Documentation #
- Webhooks — Webhook setup details
- Authentication — API key management
- SDK Reference — Python SDK documentation
- Examples — More code samples