API Reference

The Impresent API provides programmatic access to all platform features. The API is hosted on Cloudflare Workers at https://api.impresent.dev.

Authentication

All API requests (except /health) require authentication using an API key.

Getting an API Key

  1. Log in to the Impresent Dashboard
  2. Navigate to Settings > API Keys
  3. Click “Create New Key”
  4. Copy and store your key securely - it won’t be shown again

Using Your API Key

Include the API key in the Authorization header:

curl https://api.impresent.dev/api/decks \
  -H "Authorization: Bearer imp_your_api_key_here"

Base URL

https://api.impresent.dev

Response Format

All responses are JSON. Successful responses have this structure:

{
  "data": { ... },
  "meta": {
    "requestId": "req_abc123"
  }
}

Error responses:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Deck not found"
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

Endpoints

Health Check

Check if the API is running.

GET /health

Response:

{
  "status": "ok",
  "version": "1.0.0"
}

Decks

List Decks

Get all decks for the authenticated user.

GET /api/decks

Query Parameters:

ParameterTypeDescription
limitnumberMax results (default: 50, max: 100)
offsetnumberPagination offset
sortstringSort field: updated, created, title
orderstringSort order: asc, desc

Response:

{
  "data": [
    {
      "id": "deck_abc123",
      "slug": "quarterly-review",
      "title": "Q3 2024 Review",
      "templateId": "corporate",
      "createdAt": "2024-01-15T10:30:00Z",
      "updatedAt": "2024-01-15T14:22:00Z"
    }
  ],
  "meta": {
    "total": 42,
    "limit": 50,
    "offset": 0
  }
}

Create Deck

Create a new deck.

POST /api/decks

Request Body:

{
  "slug": "my-presentation",
  "title": "My Presentation",
  "markdown": "---\nmarp: true\n---\n\n# Slide 1\n\nContent here",
  "templateId": "minimal"
}
FieldTypeRequiredDescription
slugstringYesURL-friendly identifier (unique per user)
markdownstringYesFull markdown content
titlestringNoDisplay title (extracted from markdown if not provided)
templateIdstringNoTemplate ID (default: minimal)

Response:

{
  "data": {
    "id": "deck_xyz789",
    "slug": "my-presentation",
    "title": "My Presentation",
    "templateId": "minimal",
    "createdAt": "2024-01-15T10:30:00Z",
    "updatedAt": "2024-01-15T10:30:00Z"
  }
}

Get Deck

Get a deck by ID.

GET /api/decks/:id

Response:

{
  "data": {
    "id": "deck_abc123",
    "slug": "quarterly-review",
    "title": "Q3 2024 Review",
    "markdown": "---\nmarp: true\n...",
    "templateId": "corporate",
    "createdAt": "2024-01-15T10:30:00Z",
    "updatedAt": "2024-01-15T14:22:00Z"
  }
}

Get Deck by Slug

Get a deck by its slug.

GET /api/decks/by-slug/:slug

Update Deck

Update an existing deck.

PUT /api/decks/:id

Request Body:

{
  "markdown": "---\nmarp: true\n---\n\n# Updated Content",
  "title": "Updated Title",
  "templateId": "dark"
}

All fields are optional. Only provided fields are updated.

Update Single Slide

Update a single slide by index (0-based).

PATCH /api/decks/:id/slides/:index

Request Body:

{
  "content": "# Updated Slide\n\nNew content for this slide"
}

Delete Deck

Delete a deck permanently.

DELETE /api/decks/:id

Response:

{
  "data": {
    "deleted": true
  }
}

Rendering

Render Deck

Render a stored deck to HTML, PDF, or PPTX.

POST /api/decks/:id/render

Request Body:

{
  "format": "pdf"
}
FieldTypeRequiredDescription
formatstringYesOutput format: html, pdf, pptx

Response:

{
  "data": {
    "url": "https://storage.impresent.dev/renders/abc123.pdf",
    "expiresAt": "2024-01-15T11:30:00Z",
    "format": "pdf",
    "sizeBytes": 524288
  }
}

The URL is a presigned R2 URL valid for 1 hour.

Render Raw Markdown

Render markdown content directly (without storing a deck).

POST /api/render

Request Body:

{
  "markdown": "---\nmarp: true\n---\n\n# Slide 1",
  "format": "html",
  "templateId": "minimal"
}
FieldTypeRequiredDescription
markdownstringYesMarkdown content to render
formatstringYesOutput format: html, pdf, pptx
templateIdstringNoTemplate to apply

Templates

List Templates

Get available templates (built-in and user’s custom templates).

GET /api/templates

Response:

{
  "data": [
    {
      "id": "minimal",
      "name": "minimal",
      "description": "Clean, lots of whitespace, sans-serif",
      "type": "built-in"
    },
    {
      "id": "tmpl_user123",
      "name": "my-brand",
      "description": "Custom company branding",
      "type": "custom"
    }
  ]
}

Get Template

Get template details including CSS.

GET /api/templates/:id

Response:

{
  "data": {
    "id": "corporate",
    "name": "corporate",
    "description": "Professional, muted blues/grays, structured layouts",
    "css": "/* @theme corporate */\n...",
    "scaffold": "---\nmarp: true\n...",
    "manifest": {
      "variables": {
        "--primary-color": "#1e40af"
      },
      "layouts": [
        { "name": "lead", "description": "Title slide" }
      ]
    }
  }
}

Upload Custom Template

Upload a new custom template.

POST /api/templates
Content-Type: multipart/form-data

Form Fields:

FieldTypeRequiredDescription
manifestfileYestemplate.yaml file
cssfileYestheme.css file
scaffoldfileNoscaffold.md file
assetsfile[]NoAsset files (logos, backgrounds)

Delete Custom Template

Delete a custom template.

DELETE /api/templates/:id

Assets

Upload Asset

Upload an image or other binary asset.

POST /api/assets
Content-Type: multipart/form-data

Form Fields:

FieldTypeRequiredDescription
filefileYesThe file to upload
filenamestringNoCustom filename

Response:

{
  "data": {
    "id": "asset_abc123",
    "filename": "logo.png",
    "mimeType": "image/png",
    "sizeBytes": 15360,
    "uri": "asset://asset_abc123"
  }
}

Use the uri in your markdown:

![Company Logo](asset://asset_abc123)

Get Asset Metadata

GET /api/assets/:id

Get Asset URL

Get a presigned URL to download the asset.

GET /api/assets/:id/url

Response:

{
  "data": {
    "url": "https://storage.impresent.dev/assets/abc123.png",
    "expiresAt": "2024-01-15T11:30:00Z"
  }
}

Delete Asset

DELETE /api/assets/:id

Error Codes

CodeHTTP StatusDescription
UNAUTHORIZED401Missing or invalid API key
FORBIDDEN403Access denied to resource
NOT_FOUND404Resource not found
VALIDATION_ERROR400Invalid request body
CONFLICT409Resource already exists (e.g., duplicate slug)
RATE_LIMITED429Too many requests
INTERNAL_ERROR500Server error

Rate Limits

PlanRequests/minuteRenders/hour
Free6010
Pro300100
Team1000500

Rate limit headers are included in all responses:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1705315800