Connections

Connect external tools (Zoho Sprints, Jira, etc.) to power report workflows with live data. OAuth tokens are encrypted at rest and auto-refresh transparently.

How it works

  1. Authorize — call POST /v1/oauth/zoho/authorize to get an OAuth URL, open it in a browser/popup
  2. Callback — user approves, vendor redirects to our callback, tokens are encrypted and stored
  3. Configure — set vendor-specific config (e.g. workspace_id for Zoho) via PATCH /v1/connections/{id}
  4. Use — pass connection_id to workflow endpoints to pull live data

Vendor-specific configuration

Each vendor needs different post-OAuth settings in the config JSON:

VendorRequired configHow to find
Zohoworkspace_idZoho Sprints URL: sprints.zoho.in/team/XXXXXXX/...
Jiracloud_idAuto-fetched from Atlassian API (planned)
GitHuborgUser picks from accessible orgs (planned)

Endpoints

POST/v1/oauth/{vendor}/authorize

Start the OAuth flow. Returns an authorize_url to open in a browser or popup window. After the user approves, the callback stores the connection automatically.

Parameters

NameTypeRequiredDescription
integration_idstringrequiredWhich integration to connect (e.g. zoho_sprints).
display_namestringoptionalHuman-readable label for this connection (e.g. "Starweaver Zoho").
regionstringoptionalVendor region hint (e.g. in, com, eu for Zoho). Auto-detected from callback if omitted.

Response

200
{
  "authorize_url": "https://accounts.zoho.in/oauth/v2/auth?client_id=...&scope=...&state=...",
  "redirect_uri": "https://api.slideforge.dev/v1/oauth/zoho/callback"
}

Examples

curl -X POST https://api.slideforge.dev/v1/oauth/zoho/authorize \
  -H "Authorization: Bearer sf_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_id": "zoho_sprints",
    "display_name": "My Zoho Workspace"
  }'
GET/v1/connections

List all your connections with status, integrations, and config.

Response

200
{
  "connections": [
    {
      "id": "conn_abc123",
      "vendor_id": "zoho",
      "workspace_id": "60024660147",
      "display_name": "Starweaver Zoho",
      "config": {
        "workspace_id": "60024660147"
      },
      "status": "active",
      "region": "in",
      "granted_scopes": [
        "ZohoSprints.projects.READ",
        "ZohoSprints.sprints.READ"
      ],
      "integrations": [
        {
          "id": "zoho_sprints",
          "name": "Zoho Sprints",
          "category": "project_management"
        }
      ],
      "expires_at": "2026-04-18T05:35:12Z",
      "last_error": null
    }
  ],
  "count": 1
}

Examples

curl https://api.slideforge.dev/v1/connections -H "Authorization: Bearer sf_live_YOUR_KEY"
PATCH/v1/connections/{id}

Update display name or vendor-specific config. Config is merged (additive) — existing keys are preserved unless overwritten.

Parameters

NameTypeRequiredDescription
display_namestringoptionalUpdate the display name.
workspace_idstringoptionalShorthand for config.workspace_id (also updates the config JSON).
configobjectoptionalVendor-specific settings — merged into existing config. E.g. {"workspace_id": "123"}.

Response

200
{
  "id": "conn_abc123",
  "vendor_id": "zoho",
  "workspace_id": "60024660147",
  "display_name": "Starweaver Zoho",
  "config": {
    "workspace_id": "60024660147"
  },
  "status": "active"
}

Examples

curl -X PATCH https://api.slideforge.dev/v1/connections/conn_abc123 \
  -H "Authorization: Bearer sf_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"config": {"workspace_id": "60024660147"}}'
POST/v1/connections/{id}/test

Verify a connection works. Refreshes the token if needed and calls the vendor's cheapest API (e.g. list projects). Returns project names on success.

Response

200
{
  "ok": true,
  "workspace_id": "60024660147",
  "project_count": 3,
  "project_names": [
    "BOOSTR",
    "Schulich Launch Program",
    "Journeybuilder"
  ]
}

Examples

curl -X POST https://api.slideforge.dev/v1/connections/conn_abc123/test -H "Authorization: Bearer sf_live_YOUR_KEY"
DELETE/v1/connections/{id}

Revoke and permanently delete a connection. Tokens are wiped. Cannot be undone — you'll need to re-authorize.

Response

200
{
  "id": "conn_abc123",
  "status": "deleted"
}

Examples

curl -X DELETE https://api.slideforge.dev/v1/connections/conn_abc123 -H "Authorization: Bearer sf_live_YOUR_KEY"

Full example: connect and generate a report

POST/v1/workflows/agile/executive-snapshot

End-to-end: authorize OAuth, configure workspace, test, then generate a report.

Examples

import requests, time, webbrowser

API = "https://api.slideforge.dev"
KEY = "sf_live_YOUR_KEY"
H = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}

# 1. Start OAuth
auth = requests.post(f"{API}/v1/oauth/zoho/authorize", headers=H, json={
    "integration_id": "zoho_sprints",
    "display_name": "My Zoho",
}).json()
webbrowser.open(auth["authorize_url"])  # User approves in browser
input("Press Enter after approving...")

# 2. Find the new connection
conns = requests.get(f"{API}/v1/connections", headers=H).json()["connections"]
conn_id = conns[0]["id"]

# 3. Set workspace ID (Zoho team ID from your Sprints URL)
requests.patch(f"{API}/v1/connections/{conn_id}", headers=H, json={
    "config": {"workspace_id": "60024660147"}
})

# 4. Test it
test = requests.post(f"{API}/v1/connections/{conn_id}/test", headers=H).json()
print(f"Connected: {test['project_count']} projects")

# 5. Generate a report
job = requests.post(f"{API}/v1/workflows/agile/executive-snapshot", headers=H, json={
    "connection_id": conn_id,
    "theme_id": "consulting_blue",
}).json()

# 6. Poll for result
while True:
    status = requests.get(f"{API}/v1/jobs/{job['deck_id']}", headers=H).json()
    if status["status"] == "complete":
        print(status["pptx_url"])
        break
    time.sleep(3)

Token lifecycle

Auto-refresh: tokens refresh automatically when connectors need them. You never manage tokens directly.

Encryption: all tokens encrypted at rest with AES-128-CBC + HMAC-SHA256.

Status values:

  • active — working, tokens valid
  • error — last refresh failed (check last_error)
  • revoked — user revoked consent at vendor — re-authorize needed

Recovery: if a connection shows error status, call POST /test to attempt a refresh. If refresh fails, re-authorize via a new OAuth flow.