One prompt. A finished book.

Open Nellie Sign in

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

  1. Create a new Zap in Zapier
  2. Choose your trigger (e.g., “New row in Google Sheets”)
  3. 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

  1. Create another Zap with trigger: Webhooks by Zapier → Catch Hook
  2. Copy the webhook URL and use it as your webhook_url
  3. 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

  1. Add an HTTP > Make a request module
  2. Configure:
    • URL: https://api.nelliewriter.com/v1/book
    • Method: POST
    • Headers:
      • X-API-Key: Your API key
      • Content-Type: application/json
    • Body type: Raw
    • Content type: JSON
    • Request content:
      {
        "prompt": "{{1.prompt}}",
        "style": "{{1.style}}",
        "output_format": "pdf"
      }

Webhook Receiver

  1. Add a Webhooks > Custom webhook module as a trigger
  2. Copy the webhook address
  3. Use it as your webhook_url in 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

  1. Add a Webhook node as trigger
  2. Set path to /webhook/nellie
  3. 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": [embed]})

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

  1. Use environment variables: Never hardcode keys
  2. Rotate keys regularly: Especially if exposed
  3. Limit scope: Use different keys for different integrations

Webhook Reliability

  1. Always verify signatures: Prevent unauthorized access
  2. Respond quickly: Return 200 within 30 seconds
  3. Process asynchronously: Queue heavy work
  4. Handle retries: Be idempotent

Error Handling

  1. Implement retries: For transient failures
  2. Log everything: For debugging
  3. Alert on failures: Set up monitoring