Skip to main content
This page walks through common end-to-end workflows with the Devin API. Each flow includes the full sequence of API calls with code examples. For individual endpoint details, see the relevant API reference pages.

Setup

Set these environment variables before running any example:
# Required: your service user API key (starts with cog_)
export DEVIN_API_KEY="cog_your_key_here"

# Required: your organization ID (find it on Settings > Service Users)
export DEVIN_ORG_ID="your_org_id"

Getting started: API key to first session

The most common workflow — authenticate, discover your account, and create your first session.

Step 1: Verify your credentials

This step uses an enterprise-scoped endpoint. Organization-scoped service users can skip to Step 3 — you already know your org ID from the Settings page.
curl "https://api.devin.ai/v3/enterprise/self" \
  -H "Authorization: Bearer $DEVIN_API_KEY"
Response:
{
  "user_id": "svc_abc123",
  "email": "my-service-user@devin.ai",
  "name": "CI Bot"
}

Step 2: List your organizations

Enterprise service users can list all organizations:
curl "https://api.devin.ai/v3/enterprise/organizations" \
  -H "Authorization: Bearer $DEVIN_API_KEY"
Organization-scoped service users already know their org ID (it’s on the Settings > Service Users page where the key was created).

Step 3: Create a session

curl -X POST "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/sessions" \
  -H "Authorization: Bearer $DEVIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Create a Python script that analyzes CSV data"}'
Response:
{
  "session_id": "devin-abc123",
  "url": "https://app.devin.ai/sessions/devin-abc123",
  "status": "running"
}

Step 4: Poll for events

Monitor the session by polling for messages:
curl "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/sessions/devin-abc123/messages" \
  -H "Authorization: Bearer $DEVIN_API_KEY"

Full Python example

import os
import time
import requests

API_KEY = os.environ["DEVIN_API_KEY"]
ORG_ID = os.environ["DEVIN_ORG_ID"]
BASE = "https://api.devin.ai/v3"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# 1. Verify credentials
me = requests.get(f"{BASE}/enterprise/self", headers=HEADERS)
me.raise_for_status()
print(f"Authenticated as: {me.json()['name']}")

# 2. Create a session
session = requests.post(
    f"{BASE}/organizations/{ORG_ID}/sessions",
    headers={**HEADERS, "Content-Type": "application/json"},
    json={"prompt": "Create a Python script that analyzes CSV data"}
).json()
print(f"Session: {session['url']}")

# 3. Poll until complete
while True:
    status = requests.get(
        f"{BASE}/organizations/{ORG_ID}/sessions/{session['session_id']}",
        headers=HEADERS
    ).json()["status"]
    print(f"Status: {status}")
    if status in ("exit", "error", "suspended"):
        break
    time.sleep(10)

Downloading session attachments

Retrieve files produced by a session (logs, screenshots, generated code, etc.).

Step 1: Get the session

curl "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $DEVIN_API_KEY"

Step 2: List attachments

curl "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/sessions/$SESSION_ID/attachments" \
  -H "Authorization: Bearer $DEVIN_API_KEY"
Response:
{
  "items": [
    {
      "attachment_id": "att_123",
      "name": "output.py",
      "url": "https://..."
    }
  ]
}

Step 3: Download

Use the url from the attachment response to download the file directly.

Full Python example

import os
import requests

API_KEY = os.environ["DEVIN_API_KEY"]
ORG_ID = os.environ["DEVIN_ORG_ID"]
SESSION_ID = os.environ["SESSION_ID"]
BASE = "https://api.devin.ai/v3"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# List attachments
attachments = requests.get(
    f"{BASE}/organizations/{ORG_ID}/sessions/{SESSION_ID}/attachments",
    headers=HEADERS
).json()["items"]

# Download each attachment
for att in attachments:
    print(f"Downloading {att['name']}...")
    content = requests.get(att["url"]).content
    with open(att["name"], "wb") as f:
        f.write(content)
    print(f"  Saved {att['name']} ({len(content)} bytes)")

Knowledge & playbook management

Manage the context and instructions that Devin uses across sessions.

Create a knowledge note

curl -X POST "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/knowledge/notes" \
  -H "Authorization: Bearer $DEVIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Coding standards",
    "trigger": "When writing code in any repository",
    "body": "Use TypeScript strict mode. Follow existing code style. Run lint before committing."
  }'

List knowledge notes

curl "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/knowledge/notes" \
  -H "Authorization: Bearer $DEVIN_API_KEY"

Update a knowledge note

curl -X PUT "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/knowledge/notes/$NOTE_ID" \
  -H "Authorization: Bearer $DEVIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Coding standards (updated)",
    "trigger": "When writing code in any repository",
    "body": "Use TypeScript strict mode. Follow existing code style. Run lint and type-check before committing."
  }'

Delete a knowledge note

curl -X DELETE "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/knowledge/notes/$NOTE_ID" \
  -H "Authorization: Bearer $DEVIN_API_KEY"

Create a playbook

curl -X POST "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/playbooks" \
  -H "Authorization: Bearer $DEVIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "PR Review",
    "instructions": "Review the PR for bugs, security issues, and style violations. Leave inline comments."
  }'

Full Python example

import os
import requests

API_KEY = os.environ["DEVIN_API_KEY"]
ORG_ID = os.environ["DEVIN_ORG_ID"]
BASE = "https://api.devin.ai/v3"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

# Create knowledge note
note = requests.post(
    f"{BASE}/organizations/{ORG_ID}/knowledge/notes",
    headers=HEADERS,
    json={
        "name": "Coding standards",
        "trigger": "When writing code in any repository",
        "body": "Use TypeScript strict mode. Follow existing code style."
    }
).json()
print(f"Created note: {note['note_id']}")

# List all notes
notes = requests.get(
    f"{BASE}/organizations/{ORG_ID}/knowledge/notes",
    headers={"Authorization": f"Bearer {API_KEY}"}
).json()["items"]
print(f"Total notes: {len(notes)}")

# Create playbook
playbook = requests.post(
    f"{BASE}/organizations/{ORG_ID}/playbooks",
    headers=HEADERS,
    json={
        "name": "PR Review",
        "instructions": "Review the PR for bugs, security issues, and style violations."
    }
).json()
print(f"Created playbook: {playbook['playbook_id']}")

Scheduling automated sessions

Create recurring sessions that run on a schedule.

Create a schedule

curl -X POST "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/schedules" \
  -H "Authorization: Bearer $DEVIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Run the test suite and report any failures",
    "cron_schedule": "0 9 * * 1-5",
    "timezone": "America/New_York"
  }'
This creates a schedule that runs every weekday at 9 AM Eastern.

List schedules

curl "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/schedules" \
  -H "Authorization: Bearer $DEVIN_API_KEY"

Update a schedule

curl -X PATCH "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/schedules/$SCHEDULE_ID" \
  -H "Authorization: Bearer $DEVIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "cron_schedule": "0 8 * * 1-5",
    "is_enabled": true
  }'

Delete a schedule

curl -X DELETE "https://api.devin.ai/v3/organizations/$DEVIN_ORG_ID/schedules/$SCHEDULE_ID" \
  -H "Authorization: Bearer $DEVIN_API_KEY"

Full Python example

import os
import requests

API_KEY = os.environ["DEVIN_API_KEY"]
ORG_ID = os.environ["DEVIN_ORG_ID"]
BASE = "https://api.devin.ai/v3"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

# Create a daily health check schedule
schedule = requests.post(
    f"{BASE}/organizations/{ORG_ID}/schedules",
    headers=HEADERS,
    json={
        "prompt": "Run the test suite and report any failures",
        "cron_schedule": "0 9 * * 1-5",
        "timezone": "America/New_York"
    }
).json()
print(f"Created schedule: {schedule['schedule_id']}")

# List all schedules
schedules = requests.get(
    f"{BASE}/organizations/{ORG_ID}/schedules",
    headers={"Authorization": f"Bearer {API_KEY}"}
).json()["items"]

for s in schedules:
    status = "enabled" if s.get("is_enabled") else "disabled"
    print(f"  {s['schedule_id']}: {s['cron_schedule']} ({status})")

Error handling

All examples above should include error handling in production. Here’s a reusable pattern:
import requests

def api_request(method, url, headers, **kwargs):
    """Make an API request with standard error handling."""
    response = requests.request(method, url, headers=headers, **kwargs)
    try:
        response.raise_for_status()
        return response.json()
    except requests.exceptions.HTTPError as e:
        status = e.response.status_code
        if status == 401:
            raise Exception("Invalid or expired API key")
        elif status == 403:
            raise Exception("Service user lacks required permission")
        elif status == 404:
            raise Exception("Resource not found")
        elif status == 429:
            raise Exception("Rate limit exceeded — wait and retry")
        else:
            raise Exception(f"API error {status}: {e.response.text}")

Support

Need Help?

For questions about the API or to report issues, email support@cognition.ai