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.0.tar.gz (50.4 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.0-py3-none-any.whl (12.0 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for surfacedocs-0.4.0.tar.gz
Algorithm Hash digest
SHA256 28dbf6f4d4f6d31f10619e0bccddfb5a83b6b235754a8ab69c873a883b14f9d9
MD5 4a8b9f45dacd28a8e2c66102c68e7020
BLAKE2b-256 deb9d9edbd330f09ff4b7838206f8347a9c8e48f87539d4a6be1938bc6812bb9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for surfacedocs-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fbcce197aa9b72448597eba7b8ca9837e73cedb8704dbf8b6a09216a45c7fb8a
MD5 72238c22c1d6721595b80b0f5d10ecd4
BLAKE2b-256 fe4c07afabe96dded55d3a46857aea35e81068cf6f98bc76b8e6496a3d635919

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