Skip to main content

Strategies

Overview

Strategies are automated workflows that execute tasks on behalf of your users. The API models strategies in three layers:
  • Strategy Catalog — the global list of available strategy templates, each with a type, schedule, and set of required connectors
  • User Strategies — when a user enables a strategy from the catalog, a user strategy is created with their specific configuration and connector binding
  • Strategy Runs — each execution of a user strategy, whether triggered on a schedule or manually, produces a run with status tracking and optional transaction records
Strategies come in two types:
TypeBehavior
activeTriggered on-demand by the user or an agent, with an optional task description
passiveRuns automatically on a cron schedule after the user enables it
Passive strategies create a workflow schedule on enable and run unattended. Active strategies are triggered explicitly via the runs endpoint.

Quick Start

1. Browse available strategies

curl /v0/strategies \
  -H "x-juno-jwt: <token>"
The response includes every strategy in the catalog, annotated with whether the current user has enabled each one.

2. Inspect a strategy

curl "/v0/strategies/str-abc123?expand=connectors&expand=tools" \
  -H "x-juno-jwt: <token>"
Use expand=connectors to see which data connectors the strategy requires, and expand=tools to see which tools it can use.

3. Enable a strategy

curl -X POST /v0/user/strategies \
  -H "x-juno-jwt: <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_id": 1,
    "connector_id": 5,
    "configuration": {
      "risk_level": "moderate",
      "notify_on_complete": true
    }
  }'
Returns 201 Created. For passive strategies with a cron schedule, the API automatically creates a workflow schedule and triggers an initial run.

4. Trigger a run

curl -X POST /v0/user/strategies/ustr-def456/runs \
  -H "x-juno-jwt: <token>" \
  -H "Content-Type: application/json" \
  -d '{"task": "Analyze my spending from last week"}'
The task field is optional and lets the user provide context for active strategies.

5. Check run status

curl /v0/user/strategies/ustr-def456/runs/run-789abc \
  -H "x-juno-jwt: <token>"
Poll until status is completed or failed.

Strategy Catalog

Listing Strategies

GET /v0/strategies
Returns all strategies with per-user enablement status.
{
  "strategies": [
    {
      "id": 1,
      "external_id": "str-abc123",
      "name": "Insights",
      "description": "Automated financial insights from your connected accounts",
      "type": "passive",
      "cron": "0 8 * * *",
      "base_prompt": "...",
      "created_at": 1700000000000,
      "is_enabled": true,
      "user_strategy_id": 42,
      "user_strategy_external_id": "ustr-def456",
      "is_active": true
    },
    {
      "id": 2,
      "external_id": "str-xyz789",
      "name": "Smart DCA",
      "description": "Dollar-cost averaging with dynamic timing",
      "type": "passive",
      "cron": "0 9 * * 1",
      "base_prompt": "...",
      "created_at": 1700000000000,
      "is_enabled": false,
      "user_strategy_id": null,
      "user_strategy_external_id": null,
      "is_active": null
    }
  ],
  "_links": {
    "self": { "href": "/v0/strategies" },
    "user_strategies": { "href": "/v0/user/strategies" }
  }
}
When is_enabled is true, the user already has this strategy active. The is_active field indicates whether the user strategy is currently running or paused.

Strategy Detail

GET /v0/strategies/{strategy_external_id}?expand=connectors&expand=tools
Returns full strategy details with optional expansion of required connectors and available tools.
{
  "strategy": {
    "id": 1,
    "external_id": "str-abc123",
    "name": "Insights",
    "description": "Automated financial insights from your connected accounts",
    "type": "passive",
    "cron": "0 8 * * *",
    "base_prompt": "...",
    "created_at": 1700000000000
  },
  "required_connectors": [
    {
      "id": 5,
      "external_id": "con-bank01",
      "name": "Open Banking",
      "description": "Connect bank accounts via open banking",
      "icon_url": "https://cdn.example.com/icons/bank.svg",
      "auth_type": "oauth2"
    }
  ],
  "available_tools": [
    {
      "id": 10,
      "external_id": "tool-spend01",
      "name": "Spending Analyzer",
      "description": "Categorizes and analyzes transaction spending patterns",
      "tool_schema": { ... }
    }
  ],
  "_links": {
    "self": { "href": "/v0/strategies/str-abc123" },
    "strategies": { "href": "/v0/strategies" },
    "enable": { "href": "/v0/user/strategies", "method": "POST" }
  }
}
The enable link is included only when the user has not yet enabled this strategy.

User Strategies

Enabling a Strategy

POST /v0/user/strategies
Request body:
{
  "strategy_id": 1,
  "connector_id": 5,
  "configuration": {
    "risk_level": "moderate"
  }
}
FieldTypeRequiredDescription
strategy_idintegerYesID of the strategy from the catalog
connector_idintegerNoSpecific connector to bind. Required if the strategy has required connectors.
configurationobjectNoUser-specific configuration for the strategy
Response: 201 Created
{
  "user_strategy": {
    "id": 42,
    "external_id": "ustr-def456",
    "strategy": {
      "id": 1,
      "external_id": "str-abc123",
      "name": "Insights",
      "description": "...",
      "type": "passive",
      "cron": "0 8 * * *",
      "base_prompt": "...",
      "created_at": 1700000000000
    },
    "connector": {
      "id": 5,
      "external_id": "con-bank01",
      "name": "Open Banking",
      "description": "...",
      "icon_url": "https://cdn.example.com/icons/bank.svg",
      "auth_type": "oauth2"
    },
    "is_active": true,
    "configuration": { "risk_level": "moderate" },
    "created_at": 1700000060000
  },
  "_links": {
    "self": { "href": "/v0/user/strategies/ustr-def456" },
    "user": { "href": "/v0/user/me" },
    "strategy": { "href": "/v0/strategies/str-abc123" },
    "runs": { "href": "/v0/user/strategies/ustr-def456/runs" },
    "update": { "href": "/v0/user/strategies/ustr-def456", "method": "PATCH" },
    "disable": { "href": "/v0/user/strategies/ustr-def456", "method": "DELETE" }
  }
}
If the strategy requires connectors that the user has not connected, the API returns 400 Bad Request with error code UST-400-001. Connect the required connectors first, or pass a valid connector_id.

Listing User Strategies

GET /v0/user/strategies
Returns all strategies the user has enabled, with embedded strategy and connector details. Response: 200 OK
{
  "user_strategies": [
    {
      "id": 42,
      "external_id": "ustr-def456",
      "strategy": { ... },
      "connector": { ... },
      "is_active": true,
      "configuration": { "risk_level": "moderate" },
      "created_at": 1700000060000
    }
  ],
  "_links": {
    "self": { "href": "/v0/user/strategies" },
    "strategies": { "href": "/v0/strategies" }
  }
}

Getting a User Strategy

GET /v0/user/strategies/{user_strategy_external_id}
Response: 200 OK with the same user_strategy shape as above.

Updating a User Strategy

PATCH /v0/user/strategies/{user_strategy_external_id}
Request body:
{
  "is_active": false,
  "configuration": { "risk_level": "conservative" }
}
FieldTypeRequiredDescription
is_activebooleanNoPause (false) or resume (true) the strategy
configurationobjectNoReplace the user-specific configuration
Response: 200 OK with the updated user strategy. Setting is_active to false pauses the workflow schedule for passive strategies. Setting it back to true resumes it.

Disabling a Strategy

DELETE /v0/user/strategies/{user_strategy_external_id}
Response: 204 No Content Soft-deletes the user strategy and removes any associated workflow schedule. The strategy can be re-enabled from the catalog at any time.

Strategy Runs

Triggering a Run

POST /v0/user/strategies/{user_strategy_external_id}/runs
Request body (optional):
{
  "task": "Analyze my spending from last week"
}
FieldTypeRequiredDescription
taskstringNoTask description for the strategy to execute
The user_strategy_external_id path parameter accepts both ustr- prefixed user strategy IDs and str- prefixed catalog strategy IDs. When a catalog ID is provided, the API resolves it to the user’s enabled instance of that strategy. Idempotency: Pass an Idempotency-Key header to prevent duplicate runs. If a run with the same key already exists, the API returns 208 Already Reported with the original run. Response status codes depend on the trigger outcome:
StatusMeaning
201 CreatedRun created and workflow triggered successfully
202 AcceptedRun created but queued (another run is already in progress)
207 Multi-StatusRun created but the workflow trigger failed (queued for retry)
208 Already ReportedDuplicate idempotency key — original run returned
Response body:
{
  "run": {
    "id": 100,
    "external_id": "run-789abc",
    "user_strategy_id": 42,
    "user_strategy_external_id": "ustr-def456",
    "status": "queued",
    "trigger_type": "manual",
    "started_at": null,
    "completed_at": null,
    "result": null,
    "error_message": null,
    "error_code": null,
    "event_id": "wf_abc123",
    "task": "Analyze my spending from last week",
    "created_at": 1700000120000,
    "transactions": null,
    "user_strategy": null,
    "strategy": null
  },
  "trigger_status": "triggered",
  "_links": {
    "self": { "href": "/v0/user/strategies/ustr-def456/runs/run-789abc" },
    "user": { "href": "/v0/user/me" },
    "user_strategy": { "href": "/v0/user/strategies/ustr-def456" },
    "runs": { "href": "/v0/user/strategies/ustr-def456/runs" },
    "cancel": { "href": "/v0/user/strategies/ustr-def456/runs/run-789abc", "method": "DELETE" }
  }
}
Triggering a run on an inactive (paused) strategy returns 400 Bad Request with error code RUN-400-002. Resume the strategy first via PATCH.

Monitoring Run Status

GET /v0/user/strategies/{user_strategy_external_id}/runs/{run_external_id}
Use expand=transactions to include any transactions created by the run.
{
  "run": {
    "id": 100,
    "external_id": "run-789abc",
    "user_strategy_id": 42,
    "user_strategy_external_id": "ustr-def456",
    "status": "completed",
    "trigger_type": "manual",
    "started_at": 1700000121000,
    "completed_at": 1700000180000,
    "result": { "insights_generated": 3 },
    "error_message": null,
    "error_code": null,
    "event_id": "wf_abc123",
    "task": "Analyze my spending from last week",
    "created_at": 1700000120000,
    "transactions": null,
    "user_strategy": null,
    "strategy": null
  },
  "_links": {
    "self": { "href": "/v0/user/strategies/ustr-def456/runs/run-789abc" },
    "user": { "href": "/v0/user/me" },
    "user_strategy": { "href": "/v0/user/strategies/ustr-def456" },
    "runs": { "href": "/v0/user/strategies/ustr-def456/runs" },
    "cancel": { "href": "/v0/user/strategies/ustr-def456/runs/run-789abc", "method": "DELETE" }
  }
}

Run History

GET /v0/user/strategies/{user_strategy_external_id}/runs?status=completed&limit=10&offset=0
ParameterTypeDefaultDescription
statusstringFilter by run status
limitinteger20Maximum results (max 100)
offsetinteger0Pagination offset
expandstringExpand related resources: transactions, user_strategy, strategy, user_strategy.strategy
Response: 200 OK
{
  "runs": [ ... ],
  "total": 47,
  "_links": {
    "self": { "href": "/v0/user/strategies/ustr-def456/runs" },
    "user_strategy": { "href": "/v0/user/strategies/ustr-def456" }
  }
}

Cross-Strategy Run History

To list runs across all enabled strategies:
GET /v0/user/runs?limit=20&offset=0
Accepts the same status, limit, offset, and expand parameters. The expand options user_strategy, strategy, and user_strategy.strategy are useful here to identify which strategy produced each run.

Cancelling a Run

DELETE /v0/user/strategies/{user_strategy_external_id}/runs/{run_external_id}
Response: 204 No Content Only runs with status queued can be cancelled. Attempting to cancel a run in any other state returns 400 Bad Request with error code RUN-400-001.

Getting a Run by ID

When you have a run ID but not the parent strategy ID:
GET /v0/user/runs/{run_external_id}
Accepts the same expand parameter as the nested endpoint. The API verifies the run belongs to the authenticated user and returns 403 Forbidden if not.

Endpoints

MethodPathDescriptionStatus Codes
GET/v0/strategiesList all strategies with user enablement status200
GET/v0/strategies/{id}Get strategy detail with optional expand=connectors,tools200, 404
GET/v0/user/strategiesList user’s enabled strategies200
POST/v0/user/strategiesEnable a strategy201, 400, 404, 409
GET/v0/user/strategies/{id}Get an enabled strategy200, 403, 404
PATCH/v0/user/strategies/{id}Update configuration or pause/resume200, 403, 404
DELETE/v0/user/strategies/{id}Disable a strategy204, 403, 404
GET/v0/user/strategies/{id}/runsList runs for a strategy200, 403, 404
POST/v0/user/strategies/{id}/runsTrigger a new run201, 202, 207, 208, 400, 403, 404
GET/v0/user/strategies/{id}/runs/{run_id}Get a specific run200, 403, 404
DELETE/v0/user/strategies/{id}/runs/{run_id}Cancel a queued run204, 400, 403, 404
GET/v0/user/runsList all runs across strategies200
GET/v0/user/runs/{run_id}Get a run by ID (cross-strategy)200, 403, 404

Integration Patterns

Building a Strategy Selection UI

  1. Fetch the catalog with GET /v0/strategies
  2. For each strategy, check is_enabled to show the user’s current state
  3. When the user selects a strategy, fetch its detail with expand=connectors to show prerequisites
  4. If required connectors are not connected, guide the user through connector setup first
  5. Enable the strategy with POST /v0/user/strategies

Polling Run Status

After triggering a run, poll the run endpoint until status reaches a terminal state:
state = POST /v0/user/strategies/{id}/runs { task: "..." }
run_id = state.run.external_id

while state.run.status in ["queued", "running"]:
    wait(2 seconds)
    state = GET /v0/user/strategies/{id}/runs/{run_id}

if state.run.status == "completed":
    handle_success(state.run.result)
else:
    handle_failure(state.run.error_message, state.run.error_code)

Run Lifecycle

Strategy Lifecycle

Idempotent Run Triggers

For systems that may retry requests (webhooks, queues), use the Idempotency-Key header:
curl -X POST /v0/user/strategies/ustr-def456/runs \
  -H "x-juno-jwt: <token>" \
  -H "Idempotency-Key: evt_unique_12345" \
  -H "Content-Type: application/json" \
  -d '{"task": "Process daily report"}'
If the same key is sent again, the API returns 208 Already Reported with the original run instead of creating a duplicate.

Error Handling

All errors follow RFC 7807 Problem Details format:
{
  "type": "https://api.sumvin.com/errors/str-404-001",
  "title": "Strategy Not Found",
  "status": 404,
  "detail": "Strategy str-abc123 not found",
  "instance": "/v0/strategies/str-abc123",
  "error_code": "STR-404-001"
}

Strategy Errors (STR)

CodeStatusDescriptionRecovery
STR-404-001404Strategy not found in the catalogVerify the strategy external ID via GET /v0/strategies
STR-409-001409Strategy already enabled for this userUse the existing user strategy, or disable and re-enable
STR-400-001400Invalid external ID formatUse str- prefix for catalog strategies, ustr- for user strategies

User Strategy Errors (UST)

CodeStatusDescriptionRecovery
UST-404-001404User strategy not foundVerify the user strategy external ID via GET /v0/user/strategies
UST-403-001403User strategy belongs to another userVerify you are using the correct ID
UST-400-001400Missing required connectorConnect the required connectors before enabling the strategy

Strategy Run Errors (RUN)

CodeStatusDescriptionRecovery
RUN-404-001404Strategy run not foundVerify the run external ID via the runs list endpoint
RUN-403-001403Strategy run belongs to another userVerify you are using the correct run ID
RUN-409-001409Another run is already in progressWait for the current run to complete, or cancel it
RUN-400-001400Cannot cancel run (not in queued status)Only queued runs can be cancelled
RUN-400-002400Strategy is not activeResume the strategy via PATCH before triggering a run
RUN-208-001208Duplicate idempotency keyThe original run is returned in the response body

Reference Tables

Strategy Types

ValueDescription
activeTriggered on-demand by the user or an agent
passiveRuns automatically on a cron schedule

Run Statuses

ValueDescription
queuedRun created, waiting for workflow pickup
runningWorkflow is currently executing
completedWorkflow finished successfully
failedWorkflow encountered an error
cancelledRun was cancelled before execution

Trigger Types

ValueDescription
scheduledTriggered by the cron schedule
manualTriggered by an explicit API call

Trigger Statuses

Returned in the trigger_status field of the trigger response:
ValueDescription
triggeredWorkflow was dispatched successfully
queuedRun was created but another run is in progress — will execute when the current run finishes
trigger_failedWorkflow dispatch failed — run is queued for automatic retry

Connector Auth Types

ValueDescription
oauthOAuth 1.0 authentication
oauth2OAuth 2.0 authentication
api_keyAPI key authentication

Expand Parameters

EndpointExpand Options
GET /v0/strategies/{id}connectors, tools
GET .../runstransactions, user_strategy, strategy, user_strategy.strategy
GET .../runs/{id}transactions, user_strategy, strategy, user_strategy.strategy
GET /v0/user/runstransactions, user_strategy, strategy, user_strategy.strategy
GET /v0/user/runs/{id}transactions, user_strategy, strategy, user_strategy.strategy

Next Steps