Innerly API Integration Documentation

Quick Start

Prerequisites

  • HTTPS-enabled server endpoint
  • SSL certificate (required - self-signed certificates not supported)
  • Webhook URL accessible from external sources

5-Minute Setup

  1. Prepare your endpoint: Ensure your server can accept POST requests at your designated webhook URL
  2. Generate API token: Contact Innerly team to receive your production and sandbox API tokens
  3. Implement basic handler: Create a simple handler that returns {"status": "ok"} for initial testing
  4. Test connection: Use provided test payloads to verify your endpoint receives data correctly
  5. Go live: Switch from sandbox to production endpoints

Webhook API Reference

Endpoint

http
POST https://{YOUR-HOST}/{ENDPOINT}

Required: Provide both production and sandbox URLs during setup.

Headers

Header Type Description
Content-Type Required application/json
Authorization Required Bearer {API_TOKEN}
X-Signature Optional HMAC-SHA256 signature for payload verification

Request Payload

json
{
  "fieldData": {
    "name": "Post Title",
    "slug": "converted-post-title", 
    "published_date": "2025-07-04T10:30:00Z",
    "content": "<p>Post HTML content</p>",
    "description": "Post summary",
    "image": { 
      "url": "https://example.com/image.jpg" 
    },
    "alttags": "keyword1, keyword2, keyword3, keyword4, keyword5",
    "category": "Bitcoin | Ethereum | Altcoins | AI",
    "read_time": 5
  }
}

Field Specifications

Field Type Required Description SEO Enhancement
name string Yes Title (max 200) Recommend 50–60 chars for Google
slug string Yes URL slug Lowercase, hyphens, ≤ 60 chars
published_date string Yes ISO timestamp Add updated_date optional
content string (HTML) Yes HTML content Must include heading structure
description string Yes Meta excerpt 140–160 optimal for SERP preview
image.url string Yes HTTPS image ≥1200×630 px, <150KB
image.alt string Optional Image description Required for accessibility & SEO
seo_keywords string Yes 5–6 keywords Replace misleading alttags label
primary_category string Yes Top category e.g. “Bitcoin”
tags[] string[] Optional Related topics e.g. [“Layer 2”, “Argentina”]
read_time int Yes Minutes Add word_count (optional)

Response Formats

Success Response

http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "status": "ok",
  "post_id": 123
}

Error Responses

Status Code Description Retry Policy Common Causes
400 Bad Request - Validation failed No Invalid field formats, missing required fields
401 Unauthorized - Invalid token No Expired/invalid API token
403 Forbidden - Access denied No IP not allowlisted, invalid signature
429 Too Many Requests Yes, after 30s Rate limit exceeded (30 req/min)
500 Internal Server Error Yes Temporary server issues
503 Service Unavailable Yes Maintenance mode

Security Implementation

1. Bearer Token Authentication (Required)

Include your API token in every request:

http
Authorization: Bearer your-api-token-here

Security Notes:

  • Store tokens securely (environment variables, key vaults)
  • Never log or expose tokens in client-side code
  • Rotate tokens regularly (contact support for rotation)

2. IP Allowlisting (Optional)

Restrict webhook delivery to specific IP ranges. Contact support to configure your allowlist.

Benefits: Additional firewall-level protection Considerations: Ensure all your server IPs are included

Innerly signs each payload using HMAC-SHA256. Verify signatures to ensure payload integrity.

Implementation Examples

Python:

py
import hmac
import hashlib
import json

def verify_signature(payload_body, signature_header, secret):
    expected_signature = hmac.new(
        secret.encode('utf-8'),
        payload_body.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    
    # Signature format: "sha256=<hash>"
    provided_signature = signature_header.replace('sha256=', '')
    
    return hmac.compare_digest(expected_signature, provided_signature)

# Usage in your webhook handler
def webhook_handler(request):
    payload = request.body
    signature = request.headers.get('X-Signature', '')
    
    if not verify_signature(payload, signature, YOUR_WEBHOOK_SECRET):
        return {"error": "Invalid signature"}, 401
    
    # Process the webhook...
    return {"status": "ok"}

Node.js:

javascript
const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
    const expectedSignature = crypto
        .createHmac('sha256', secret)
        .update(payload, 'utf8')
        .digest('hex');
    
    const providedSignature = signature.replace('sha256=', '');
    
    return crypto.timingSafeEqual(
        Buffer.from(expectedSignature, 'hex'),
        Buffer.from(providedSignature, 'hex')
    );
}

PHP:

php
function verifySignature($payload, $signature, $secret) {
    $expectedSignature = hash_hmac('sha256', $payload, $secret);
    $providedSignature = str_replace('sha256=', '', $signature);
    
    return hash_equals($expectedSignature, $providedSignature);
}

4. Rate Limiting

  • Current limit: 30 requests per minute
  • 429 responses: Wait 30 seconds before retrying
  • Best practice: Implement exponential backoff for retries

Error Handling & Troubleshooting

Retry Logic Implementation

py
import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_session_with_retries():
    session = requests.Session()
    
    retry_strategy = Retry(
        total=3,
        status_forcelist=[429, 500, 502, 503, 504],
        method_whitelist=["HEAD", "GET", "POST"],
        backoff_factor=1
    )
    
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("http://", adapter)
    session.mount("https://", adapter)
    
    return session

Common Issues & Solutions

Issue: 400 Bad Request

Cause: Invalid payload format Solution:

  • Validate all required fields are present
  • Check field data types match specification
  • Ensure HTML content is properly escaped

Issue: 401 Unauthorized

Cause: Invalid or missing API token Solution:

  • Verify token is correct and not expired
  • Check Authorization header format
  • Contact support for token rotation

Issue: 403 Forbidden

Cause: IP allowlisting or signature verification failure Solution:

  • Verify your server IP is allowlisted
  • Check HMAC signature implementation
  • Ensure shared secret is correct

Debugging Tips

  1. Log request/response headers for authentication issues
  2. Validate JSON payload before sending
  3. Test with sandbox environment first
  4. Monitor response times for performance issues

Testing & Validation

Test Payloads

Use these payloads to test your webhook implementation:

Basic Test Payload

json
{
  "fieldData": {
    "name": "Test Article",
    "slug": "test-article",
    "published_date": "2025-07-04T12:00:00Z",
    "content": "<p>This is a test article content.</p>",
    "description": "Test article description",
    "image": { "url": "https://example.com/test-image.jpg" },
    "alttags": "test, article, sample, demo, innerly",
    "category": "Bitcoin",
    "read_time": 3
  }
}

Testing Checklist

  • [ ] Endpoint returns 200 OK with valid JSON response
  • [ ] Authentication header is properly validated
  • [ ] HMAC signature verification works (if implemented)
  • [ ] Error responses are handled gracefully
  • [ ] Payload parsing handles all field types correctly
  • [ ] Response format matches specification
  • [ ] Rate limiting is respected

cURL Testing Examples

Basic webhook simulation:

bash
curl -X POST 'https://your-webhook-url.com/webhook'   -H 'Authorization: Bearer YOUR_API_TOKEN'   -H 'Content-Type: application/json'   -d '{
    "fieldData": {
      "name": "Test Article",
      "slug": "test-article",
      "published_date": "2025-07-04T12:00:00Z",
      "content": "<p>Test content</p>",
      "description": "Test description",
      "image": {"url": "https://example.com/image.jpg"},
      "alttags": "test, webhook, api",
      "category": "Bitcoin",
      "read_time": 2
    }
  }'

Testing with signature:

bash
# Generate signature first, then:
curl -X POST 'https://your-webhook-url.com/webhook'   -H 'Authorization: Bearer YOUR_API_TOKEN'   -H 'Content-Type: application/json'   -H 'X-Signature: sha256=YOUR_CALCULATED_SIGNATURE'   -d @test-payload.json
FAQ
Innerly API Integration
Do I need an SSL certificate for my webhook endpoint?
Yes, HTTPS with a valid SSL certificate is mandatory. Self-signed certificates are not supported.
How do I get my API tokens?
Contact the Innerly team to receive your production and sandbox API tokens. Both will be provided during setup.
What's the difference between sandbox and production environments?
Sandbox is for testing without affecting live data. Production is for actual content delivery. You need to provide URLs for both during setup.
Can I test without a public URL?
No, your webhook URL must be accessible from external sources. For local development, consider using tunneling services like ngrok.
What authentication is required?
Bearer token authentication is required. Include Authorization: Bearer {API_TOKEN} in every request header.
Is HMAC signature verification mandatory?
No, it's optional but recommended. The signature comes in the X-Signature header as sha256=<hash>.
How does IP allowlisting work?
It's optional. Contact support to configure your allowlist if you want to restrict webhook delivery to specific IP ranges.
What should I do with my API tokens?
Store tokens securely (environment variables, key vaults), never expose in client-side code, and contact support for rotation when needed.
What does the "alttags" field contain?
Despite its name, it contains 5-6 comma-separated keywords for SEO purposes, not image alt text.
What format should the content field use?
HTML format is required. Include proper heading structure for SEO optimization.
What are the image requirements?
Must be HTTPS URL. Recommended: ≥1200×630 px, <150KB. The image.alt field is optional but recommended for accessibility.
Is the category field single or multiple choice?
The example shows pipe-separated values: "Bitcoin | Ethereum | Altcoins | AI", suggesting multiple categories are supported.
What should my endpoint return for success?
Return HTTP 200 with JSON: {"status": "ok", "post_id": 123}. The post_id field appears to be optional.
Which errors trigger retries?
According to the retry policy: 429, 500, 503: Will retry. 400, 401, 403: No retry.
When should I retry after rate limiting?
Wait 30 seconds before retrying when you receive a 429 response.
What's the rate limit?
30 requests per minute. Exceeding this returns a 429 status code.
How should I implement retries?
The documentation provides example code with exponential backoff, retrying 3 times for status codes 429, 500, 502, 503, 504.
Common causes for 400 Bad Request?
Missing required fields, Invalid field formats, Field data types don't match specification, HTML content not properly escaped.
Why might I get 401 Unauthorized?
Invalid or expired API token, Incorrect Authorization header format, Token not included in request.
What causes 403 Forbidden?
Your IP is not allowlisted (if using IP restriction), HMAC signature verification failure (if implemented).
How do I verify my HMAC implementation?
Code examples are provided for Python, Node.js, and PHP. Key points: Remove "sha256=" prefix from signature header, Use UTF-8 encoding, Use timing-safe comparison functions.
What test payload should I use?
The documentation provides a complete test payload with all required fields. Use this for initial testing.
How can I test with cURL?
Examples are provided for basic testing and testing with signatures. Ensure you replace placeholder values with your actual tokens and URLs.
What should I verify during testing?
The testing checklist covers: 200 OK response with valid JSON, Authentication validation, HMAC verification (if implemented), Error handling, Field parsing, Rate limit compliance.
How often is the API updated?
The documentation shows "Last updated: July 2025" but doesn't specify update frequency or notification methods.
Where can I find more help?
The documentation doesn't specify support channels. Contact the Innerly team who provided your API tokens for assistance.