Internal API Reference

Complete documentation for all Funl API endpoints with examples and parameters.

Overview

Funl provides a comprehensive REST API with 18 endpoints for programmatic funnel management. All endpoints require API key authentication with Pro plan or higher.

Authentication

Include your API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Get your API key from Account Settings. Pro plan or higher required.

Base URL

https://funl.ad/api/internal/v1

Funnels

List Funnels

GET /funnels

Returns all funnels (projects) for the authenticated user.

Response:

{
  "status": "success",
  "data": [
    {
      "id": "...",
      "name": "...",
      "created_at": "2025-06-04T08:00:00+00:00",
      "updated_at": "2025-06-04T08:00:00+00:00",
      "deploy_url": "https://...",
      "status": "..."
    }
  ]
}

Create Funnel

POST /funnels

Create a new funnel for the authenticated user. Optionally apply a template during creation.

Request Body:

{
  "name": "My Funnel",
  "template_id": "snow-template" // optional
}

Response:

{
  "status": "success",
  "data": {
    "id": "...",
    "name": "My Funnel",
    "created_at": "2025-06-04T08:00:00+00:00",
    "updated_at": "2025-06-04T08:00:00+00:00",
    "deploy_url": null,
    "status": null
  }
}

Get Funnel Details

GET /funnels/:id

Returns details for a single funnel owned by the authenticated user.

Response:

{
  "status": "success",
  "data": {
    "id": "...",
    "name": "...",
    "created_at": "2025-06-04T08:00:00+00:00",
    "updated_at": "2025-06-04T08:00:00+00:00",
    "deploy_url": "https://...",
    "status": "..."
  }
}

Update Funnel

PATCH /funnels/:id

Update funnel name.

Request Body:

{
  "name": "New Funnel Name"
}

Response:

{
  "status": "success",
  "data": {
    "id": "...",
    "name": "New Funnel Name",
    "created_at": "2025-06-04T08:00:00+00:00",
    "updated_at": "2025-06-04T08:01:00+00:00",
    "deploy_url": "https://...",
    "status": "..."
  }
}

Delete Funnel

DELETE /funnels/:id

Deletes the specified funnel.

Response:

{
  "status": "success"
}

Deploy Funnel

POST /funnels/:id/deploy

Deploys the specified funnel. This will trigger a deployment and update the funnel's deploy_url and status.

Response:

{
  "status": "success",
  "data": {
    "id": "...",
    "deploy_url": "https://funl.ad/user-sites/{id}/index.html",
    "status": "deployed"
  }
}

Get Funnel Content

GET /funnels/:id/content

Returns all files and content for a funnel.

Response:

{
  "status": "success",
  "data": {
    "src/index.html": "<!DOCTYPE html>...",
    "src/css/style.css": "body { ... }",
    "src/js/script.js": "document.addEventListener..."
  },
  "meta": {
    "funnel_id": "funnel-uuid",
    "last_modified": "2025-06-13T10:30:00Z",
    "total_files": 3
  }
}

Update Funnel Content

PUT /funnels/:id/content

Updates the content files for a funnel with smart file path normalization.

Request Body:

{
  "files": {
    "src/index.html": "<!DOCTYPE html>...",
    "src/css/style.css": "body { ... }"
  },
  "message": "Updated headline and styling"
}

Response:

{
  "status": "success",
  "data": {
    "funnel_id": "funnel-uuid",
    "updated_files": 2,
    "message": "Updated headline and styling",
    "timestamp": "2025-06-13T10:35:00Z"
  }
}
Smart File Path Normalization

This endpoint features intelligent file matching:

  • • Exact path matching first (src/index.htmlsrc/index.html)
  • • Basename matching if no exact match (index.html updates existing src/index.html)
  • • Automatic directory placement for new files
  • • Duplicate prevention via basename matching

Assign Custom Domain

POST /funnels/:id/assign-domain

Assigns a custom domain to a funnel for professional branding. Only available for Pro, Team, and Enterprise plans.

Request Body:

{
  "domain": "example.com"
}

Response:

{
  "status": "success",
  "data": {
    "funnel_id": "funnel-uuid",
    "domain": "example.com",
    "assigned_at": "2025-06-15T10:30:00Z"
  }
}
Domain Requirements
  • • Domain format: example.com (no http/https or www)
  • • One domain per funnel maximum
  • • DNS configuration required after assignment
  • • Pro plan or higher required

Remove Custom Domain

POST /funnels/:id/remove-domain

Removes a custom domain assignment from a funnel, reverting it back to the default funl.ad subdomain.

Response:

{
  "status": "success",
  "data": {
    "funnel_id": "funnel-uuid",
    "removed_domain": "example.com",
    "removed_at": "2025-06-15T10:30:00Z"
  }
}

Templates

Template ID Consistency

Both list and get template endpoints use the template's internal id field from the JSON data, ensuring all listed templates are accessible via the get endpoint.

List Templates

GET /templates

Returns all available templates with metadata. Uses each template's internal ID field.

Response:

{
  "status": "success",
  "data": [
    {
      "id": "snow-template",
      "name": "Snow Template",
      "category": "Advertorials",
      "steps": 2,
      "description": "A winter-themed toothbrush funnel template",
      "previewImage": "snow.png"
    }
  ]
}

Get Template Details

GET /templates/:id

Returns complete template data including all files. Searches by the template's internal ID field (not filename).

Response:

{
  "status": "success",
  "data": {
    "id": "snow-template",
    "category": "Advertorials",
    "steps": 2,
    "name": "Snow Template",
    "description": "A winter-themed toothbrush funnel template",
    "previewImage": "snow.png",
    "files": {
      "src/index.html": "<!DOCTYPE html>...",
      "src/css/style.css": "body { ... }",
      "src/js/script.js": "document.addEventListener..."
    }
  }
}

Images

Upload Image

POST /images/upload

Upload images to Supabase Storage for use in funnels.

Request:

Content-Type: multipart/form-data

Body: image file (PNG, JPG, GIF, WebP - max 5MB)

Response:

{
  "status": "success",
  "data": {
    "id": "image-uuid",
    "name": "hero-image.jpg",
    "url": "https://storage.supabase.co/...",
    "size": 1024567,
    "mime_type": "image/jpeg",
    "uploaded_at": "2025-06-13T10:30:00Z"
  }
}

Upload Image from URL

POST /images/upload-from-url

Download an image from a URL and upload it to your project storage.

Request Body:

{
  "url": "https://example.com/image.jpg",
  "project_id": "project-uuid-123",
  "filename": "my-image.jpg"
}

Response:

{
  "status": "success",
  "data": {
    "id": "image-uuid",
    "name": "my-image-123456.jpg",
    "url": "https://storage.supabase.co/...",
    "size": 1024567,
    "mime_type": "image/jpeg",
    "uploaded_at": "2025-06-13T10:30:00Z",
    "source_url": "https://example.com/image.jpg"
  }
}
Notes
  • • Image must be publicly accessible via HTTP/HTTPS
  • • Supports JPG, PNG, GIF, WebP formats
  • • Maximum file size: 5MB
  • project_id is required - must be a valid project owned by the user
  • • Auto-adds timestamp to ensure uniqueness

List Images

GET /images

List all uploaded images for the authenticated user.

Response:

{
  "status": "success",
  "data": [
    {
      "id": "image-uuid",
      "name": "hero-image.jpg", 
      "url": "https://storage.supabase.co/...",
      "size": 1024567,
      "mime_type": "image/jpeg",
      "uploaded_at": "2025-06-13T10:30:00Z"
    }
  ]
}

Delete Image

DELETE /images/:id

Delete an uploaded image.

Response:

{
  "status": "success"
}

File Operations

Delete Individual File

DELETE /funnels/:id/files/:filename

Delete a specific non-image file from a funnel's file structure.

URL Parameters:

  • :id - Funnel ID (must be owned by authenticated user)
  • :filename - File path to delete (URL-encoded if contains special characters)

Response:

{
  "status": "success",
  "data": {
    "funnel_id": "funnel-uuid",
    "deleted_file": "src/old-page.html",
    "remaining_files": 3
  }
}
Important Notes
  • • File deletion is permanent and cannot be undone
  • • Image files are blocked - use Image API for complete image deletion
  • • Filename supports URL encoding for special characters
  • • Supported file types: HTML, CSS, JS, JSON, TXT, MD, XML, etc.

Rename File

PUT /funnels/:id/files/:filename/rename

Rename or move a non-image file within a funnel while preserving its content.

Request Body:

{
  "new_name": "src/new-page.html"
}

Response:

{
  "status": "success",
  "data": {
    "funnel_id": "funnel-uuid", 
    "old_name": "src/old-page.html",
    "new_name": "src/new-page.html"
  }
}
Features
  • • Both old and new filenames support URL encoding
  • • Cannot rename to existing filename (prevents overwrites)
  • • File content is preserved during rename operation
  • • Can be used to move files between directories

Error Responses

All endpoints may return these standard error responses:

  • 401 Unauthorized — Missing or invalid API key
  • 403 Forbidden — Revoked key or insufficient plan
  • 400 Bad Request — Missing or invalid parameters
  • 404 Not Found — Resource not found or not owned by user
  • 500 Internal Server Error — Server/database error

Plan Requirements

  • Free Plan: Basic funnel operations only
  • Starter Plan: Templates + basic file operations
  • Pro Plan: Images, domains, analytics, AI features
  • Team/Enterprise Plan: All features + collaboration