DaySurface
REST API

Overview

REST API overview, base URL, and quick start

The REST API exposes the same Gmail, PDF, and webhook tools your assistant gets over MCP as authenticated HTTP endpoints - one shared service registry behind all three transports, so behavior never drifts between them.

Reach for it when the caller is your own code rather than an agent: a cron job that triages overnight mail, a backend that files attachments, a script that drafts on your behalf.

Base URL

https://api.daysurface.com

The API shares one process with the MCP server, so the same deployment also answers MCP traffic at mcp.daysurface.com/mcp; api.daysurface.com is the canonical vanity host for REST. (daysurface.com is the product site, a separate service.)

Every example in these docs uses that host. Running the server yourself? Swap in your own deployment, or http://localhost:8000 when it is running locally via daysurface-serve.

Quick Example

Rank the ten threads that most need attention:

curl -X POST https://api.daysurface.com/api/v1/services/gmail_curate_inbox \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"limit": 10}'

Every tool follows the same shape - POST /api/v1/services/{tool_name} with the tool's input model as the body. The generated OpenAPI document lives at /openapi.json.

Discovery

The root path describes the deployment to whoever - or whatever - lands on it. No authentication required.

curl https://mcp.daysurface.com/
{
  "title": "DaySurface",
  "protocol": "mcp",
  "instructions": "This host serves the Model Context Protocol at https://mcp.daysurface.com/mcp ...",
  "mcp": {
    "url": "https://mcp.daysurface.com/mcp",
    "transport": "streamable-http",
    "authentication": { "required": true, "schemes": ["oauth2", "api_key"] },
    "tools": ["gmail_list_inbox", "gmail_compose", "..."]
  },
  "endpoints": { "mcp": "...", "health": "...", "server_card": "..." }
}

Browsers (Accept: text/html) get a small landing page with the same content.

Unknown paths return a 404 carrying the same endpoints map plus a did_you_mean hint, so a client probing a legacy transport path - /sse, /messages - is told where the endpoint actually lives:

{
  "error": {
    "code": "not_found",
    "message": "No handler for GET /sse. Did you mean https://mcp.daysurface.com/mcp?",
    "details": { "path": "/sse", "did_you_mean": "https://mcp.daysurface.com/mcp" },
    "request_id": "eee3ed63ac4b4651ab3911c47a21603e"
  },
  "endpoints": {
    "mcp": "https://mcp.daysurface.com/mcp",
    "health": "https://mcp.daysurface.com/health",
    "server_card": "https://mcp.daysurface.com/.well-known/mcp/server-card.json"
  }
}

endpoints sits beside error, carrying the same entries as the discovery response above. did_you_mean is present only when a known alias matches.

Health Check

/health is the public liveness probe. No authentication required, and the response is deliberately minimal - it carries no build identity and no per-component breakdown.

curl https://api.daysurface.com/health
{ "status": "ok" }

Liveness only: the endpoint answers 200 with a fixed body whenever the process is serving, and deliberately runs no dependency probes. Readiness - whether the database, Redis and Stripe are actually reachable - is on /health/detail below, so that a slow or hanging dependency can never stall the probe a platform healthcheck restarts the container over.

Detailed health

The full payload - version, commit and per-component status - requires authentication.

curl -H "X-API-KEY: $DAYSURFACE_API_KEY" https://api.daysurface.com/health/detail
{
  "status": "ok",
  "version": "0.1.1",
  "commit": "a1b2c3d",
  "timestamp": "2025-01-15T10:30:00+00:00",
  "components": {
    "api": { "status": "ok" },
    "database": { "status": "ok" },
    "redis": { "status": "not_configured" },
    "stripe": { "status": "ok" }
  }
}

Next Steps

目录