Skip to main content

Python SDK for SurfaceDocs - Save LLM-generated documents

Project description

SurfaceDocs Python SDK

Save LLM-generated documents to SurfaceDocs.

Installation

pip install surfacedocs

Quick Start

from surfacedocs import SurfaceDocs, DOCUMENT_SCHEMA, SYSTEM_PROMPT
from openai import OpenAI

# Initialize clients
openai = OpenAI()
docs = SurfaceDocs(api_key="sd_live_...")

# Generate a document with your LLM
response = openai.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": "Document our REST API authentication flow"},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "surfacedocs_document",
            "schema": DOCUMENT_SCHEMA,
        },
    },
)

# Save to SurfaceDocs
result = docs.save(response.choices[0].message.content)
print(result.url)  # https://app.surfacedocs.dev/d/abc123

What's Included

The SDK provides three exports:

Export Type Purpose
DOCUMENT_SCHEMA dict JSON schema for LLM structured output
SYSTEM_PROMPT str Instructions for LLM to generate documents
SurfaceDocs class HTTP client to save documents

API Reference

SurfaceDocs

from surfacedocs import SurfaceDocs

# Initialize with API key
client = SurfaceDocs(api_key="sd_live_...")

# Or use environment variable
# export SURFACEDOCS_API_KEY=sd_live_...
client = SurfaceDocs()

save(content, folder_id=None)

Save a document from LLM output.

# From JSON string
result = client.save(response.choices[0].message.content)

# From dict
result = client.save({
    "title": "My Document",
    "blocks": [{"type": "paragraph", "content": "Hello world"}]
})

# To specific folder
result = client.save(content, folder_id="folder_abc123")

save_raw(title, blocks, folder_id=None, metadata=None)

Save a document with explicit parameters.

result = client.save_raw(
    title="API Documentation",
    blocks=[
        {"type": "heading", "content": "Authentication", "metadata": {"level": 1}},
        {"type": "paragraph", "content": "Use Bearer tokens for auth."},
        {"type": "code", "content": "curl -H 'Authorization: Bearer ...'", "metadata": {"language": "bash"}},
    ],
    metadata={"source": "doc-generator", "version": "1.0"},
)

get_document(document_id)

Retrieve a document by ID.

doc = client.get_document("doc_abc123")
print(doc.title)                # "API Documentation"
print(doc.blocks[0].type)      # "heading"
print(doc.blocks[0].content)   # "Authentication"

delete_document(document_id)

Delete a document by ID.

client.delete_document("doc_abc123")

create_folder(name, parent_id=None)

Create a new folder.

folder = client.create_folder("API Docs")
print(folder.id)    # "fld_abc123"
print(folder.name)  # "API Docs"

# Create a subfolder
subfolder = client.create_folder("v2", parent_id=folder.id)

list_folders(parent_id=None)

List folders, optionally filtered by parent.

# List all root folders
folders = client.list_folders()

# List subfolders of a specific folder
subfolders = client.list_folders(parent_id="fld_abc123")

SaveResult

Both save() and save_raw() return a SaveResult:

result.id        # "doc_abc123"
result.url       # "https://app.surfacedocs.dev/d/doc_abc123"
result.folder_id # "folder_xyz"

Document

Returned by get_document():

doc.id            # "doc_abc123"
doc.url           # "https://app.surfacedocs.dev/d/doc_abc123"
doc.folder_id     # "folder_xyz"
doc.title         # "My Document"
doc.content_type  # "markdown"
doc.visibility    # "private"
doc.blocks        # list[Block]
doc.metadata      # dict or None
doc.created_at    # "2024-01-01T00:00:00Z"
doc.updated_at    # "2024-01-02T00:00:00Z"

Block

Each document contains a list of Block objects:

block.id        # "blk_abc123"
block.order     # 0
block.type      # "heading", "paragraph", "code", etc.
block.content   # "Hello world"
block.metadata  # {"level": 1} or None

Folder

Returned by create_folder() and list_folders():

folder.id         # "fld_abc123"
folder.name       # "API Docs"
folder.parent_id  # "fld_parent" or None
folder.path       # "/API Docs"
folder.depth      # 0
folder.created_at # "2024-01-01T00:00:00Z"

DOCUMENT_SCHEMA

JSON schema dict for LLM structured output. Pass directly to your LLM provider.

SYSTEM_PROMPT

System prompt string to instruct LLMs on document format.

from surfacedocs import SYSTEM_PROMPT

messages = [
    {"role": "system", "content": SYSTEM_PROMPT},
    {"role": "user", "content": "Document the login flow"},
]

Block Types

Documents are composed of blocks:

Type Description Metadata
heading Section header level (1-6)
paragraph Body text -
code Code block language (optional)
list Bullet/numbered list listType ("bullet" or "ordered")
quote Block quote -
table Markdown table -
image Image url (required), alt (optional)
divider Horizontal rule -

Text content supports inline markdown: **bold**, *italic*, `code`, [link](url)

Error Handling

from surfacedocs import (
    SurfaceDocs,
    SurfaceDocsError,
    AuthenticationError,
    DocumentNotFoundError,
    FolderNotFoundError,
    ValidationError,
)

try:
    result = client.save(content)
except AuthenticationError:
    print("Invalid API key")
except ValidationError as e:
    print(f"Invalid document: {e}")
except SurfaceDocsError as e:
    print(f"API error: {e}")

try:
    doc = client.get_document("doc_abc123")
except DocumentNotFoundError:
    print("Document does not exist")

try:
    folder = client.create_folder("Docs", parent_id="fld_nonexistent")
except FolderNotFoundError:
    print("Parent folder does not exist")

Environment Variables

# API key (alternative to passing in code)
export SURFACEDOCS_API_KEY=sd_live_...

Examples

OpenAI

from surfacedocs import SurfaceDocs, DOCUMENT_SCHEMA, SYSTEM_PROMPT
from openai import OpenAI

openai = OpenAI()
docs = SurfaceDocs()

response = openai.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": "Write documentation for user authentication"},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {"name": "document", "schema": DOCUMENT_SCHEMA},
    },
)

result = docs.save(response.choices[0].message.content)
print(f"Saved: {result.url}")

Anthropic

Using Claude's structured outputs with tool use:

from surfacedocs import SurfaceDocs, DOCUMENT_SCHEMA, SYSTEM_PROMPT
import anthropic

client = anthropic.Anthropic()
docs = SurfaceDocs()

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=4096,
    system=SYSTEM_PROMPT,
    messages=[
        {"role": "user", "content": "Write documentation for user authentication"},
    ],
    tools=[{
        "name": "create_document",
        "description": "Create a structured document",
        "input_schema": DOCUMENT_SCHEMA,
    }],
    tool_choice={"type": "tool", "name": "create_document"},
)

tool_use = next(b for b in response.content if b.type == "tool_use")
result = docs.save(tool_use.input)
print(f"Saved: {result.url}")

Google Gemini

Using Gemini's structured output with JSON schema:

from surfacedocs import SurfaceDocs, DOCUMENT_SCHEMA, SYSTEM_PROMPT
import google.generativeai as genai

genai.configure(api_key="...")
docs = SurfaceDocs()

model = genai.GenerativeModel(
    model_name="gemini-2.0-flash",
    system_instruction=SYSTEM_PROMPT,
    generation_config=genai.GenerationConfig(
        response_mime_type="application/json",
        response_schema=DOCUMENT_SCHEMA,
    ),
)

response = model.generate_content("Write documentation for user authentication")
result = docs.save(response.text)
print(f"Saved: {result.url}")

Manual Document

from surfacedocs import SurfaceDocs

docs = SurfaceDocs()

result = docs.save_raw(
    title="Meeting Notes",
    blocks=[
        {"type": "heading", "content": "Action Items", "metadata": {"level": 1}},
        {"type": "list", "content": "- Review PR #123\n- Update docs", "metadata": {"listType": "bullet"}},
        {"type": "divider", "content": ""},
        {"type": "paragraph", "content": "Next meeting: Monday 10am"},
    ],
    metadata={"source": "meeting-bot"},
)

Managing Documents

from surfacedocs import SurfaceDocs, DocumentNotFoundError

docs = SurfaceDocs()

# Save a document
result = docs.save_raw(
    title="API Guide",
    blocks=[{"type": "paragraph", "content": "Welcome to the API."}],
)

# Retrieve it
doc = docs.get_document(result.id)
print(doc.title)  # "API Guide"

# Delete it
docs.delete_document(result.id)

Managing Folders

from surfacedocs import SurfaceDocs

docs = SurfaceDocs()

# Create a folder hierarchy
parent = docs.create_folder("Engineering")
child = docs.create_folder("Backend", parent_id=parent.id)

# List root folders
for folder in docs.list_folders():
    print(folder.name)

# List subfolders
for folder in docs.list_folders(parent_id=parent.id):
    print(f"  {folder.name}")

# Save a document to a folder
result = docs.save_raw(
    title="Architecture Overview",
    blocks=[{"type": "paragraph", "content": "Our system uses..."}],
    folder_id=child.id,
)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

surfacedocs-0.4.1.tar.gz (52.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

surfacedocs-0.4.1-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file surfacedocs-0.4.1.tar.gz.

File metadata

  • Download URL: surfacedocs-0.4.1.tar.gz
  • Upload date:
  • Size: 52.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.0

File hashes

Hashes for surfacedocs-0.4.1.tar.gz
Algorithm Hash digest
SHA256 97d4c5c45d06f6226e9bc4e0e609d91d1290f5decddac19d87a3158365c6c235
MD5 09cc473c16ffa982f8e4f71cfe15340c
BLAKE2b-256 b4fac43461b0a93d30a40a286c4a002f9bb561a6ef34fbc0d900bfdab300ea27

See more details on using hashes here.

File details

Details for the file surfacedocs-0.4.1-py3-none-any.whl.

File metadata

File hashes

Hashes for surfacedocs-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ecaaa3b525b9caf980efb1b3896ba7e5a72a70c042211fd9341682f49c6c1329
MD5 1125777ff55ff7b98f3471c3b1719ba6
BLAKE2b-256 79a22bcd6def4ca51db1b261b66480db151929a4f2024fa3cb16a877c1fc2340

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page