# Deck v2 API Context
Deck is a platform that connects to external websites on behalf of your users. You make REST API calls, Deck handles authentication, navigation, and data extraction, and returns structured JSON results. You never interact with websites directly.
## API Basics
- Base URL: `https://api.deck.co/v2`
- Auth: `Authorization: Bearer sk_live_...`
- Content type: `application/json`
- All work is asynchronous. API calls return immediately. Results arrive via events.
- There is no sandbox or test environment. All calls are live.
## Core Integration Flow
1. Create an **Agent** (a use case that groups related tasks, e.g. hotel reservations)
2. Create a **Source** (an external website, defined by type and URL)
3. Store a **Credential** (encrypted auth details for a user on a source)
4. Create a **Task** (defines what to do; belongs to an agent, runs on any supporting source)
5. Run the **Task** with a credential (Deck creates a session, authenticates, and executes)
6. Receive results via **Events** pushed to your webhook or queue
## Resource ID Prefixes
Every resource ID is prefixed by type:
| Prefix | Resource |
| --- | --- |
| `agt_` | Agent |
| `src_` | Source |
| `cred_` | Credential |
| `sess_` | Session |
| `task_` | Task |
| `trun_` | Task Run |
| `wflo_` | Workflow |
| `wrun_` | Workflow Run |
| `trg_` | Trigger |
| `tgrn_` | Trigger Run |
| `stor_` | Storage Item |
| `evt_` | Event |
| `evtd_` | Event Destination |
| `edlv_` | Event Delivery |
| `req_` | Request ID |
## Key Endpoints
| Action | Method | Path |
| --- | --- | --- |
| Create agent | POST | `/v2/agents` |
| Create source | POST | `/v2/sources` |
| Store credential | POST | `/v2/credentials` |
| Delete credential | DELETE | `/v2/credentials/{credential_id}` |
| Create task | POST | `/v2/tasks` |
| Run task | POST | `/v2/tasks/{task_id}/run` |
| Submit interaction | POST | `/v2/task-runs/{run_id}/interaction` |
| List task runs | GET | `/v2/task-runs` |
| Get task run | GET | `/v2/task-runs/{run_id}?include=input,storage,artifacts` |
| Create workflow | POST | `/v2/workflows` |
| Run workflow | POST | `/v2/workflows/{workflow_id}/run` |
| Get workflow run | GET | `/v2/workflow-runs/{workflow_run_id}` |
| Create trigger | POST | `/v2/triggers` |
| Create event destination | POST | `/v2/event-destinations` |
## Credential Authentication
Most sources use `username_password`:
```json
{
"source_id": "src_...",
"auth_method": "username_password",
"auth_credentials": { "username": "...", "password": "..." }
}
```
Valid `auth_method` values: `username_password`, `source_fields`, `none`.
## Credential Statuses
`unverified` → `verified` → (optionally `invalid`) → `deleted`
- `unverified` means stored but not yet used in a successful authentication
- `verified` means successfully authenticated at least once
- `invalid` means the source rejected the credentials
- `deleted` means permanently removed from the vault
## Session Statuses
Sessions are created automatically when a task runs: `queued` → `running` → `idle` (no active tasks) → `completing` → `completed` | `failed`
You can reuse a session by passing `session_id` when running a task.
## Interactions
When a task run needs user input (MFA, security question, account selection), status becomes `interaction_required`. The response includes an `interaction` object with `type`, `message`, and `fields`. Each field has a `name`, `type`, and `label`. Submit the response to:
- Task runs: `POST /v2/task-runs/{run_id}/interaction`
Body: `{ "input": { "<field_name>": "<value>" } }`
## Workflows
Use a workflow whenever one task run's output decides or feeds the next one. Signs you need a workflow instead of separate task runs:
- You would wait for a run to finish, read its output, and then start another run with values from it.
- A task returns a list (accounts, reservations, orders) and you need to run another task for each item.
- A later task should run only if an earlier one found something (a price drop, a new bill, a cancellable booking).
- Several tasks need the same login on the same source, in order.
Do not use a workflow for a single task, for work that should run in parallel, or when each item needs different values from your own database (workflow steps take one set of run-time values, not one per item).
A workflow is an ordered array of steps, each referencing a task by `task_id`. Steps run one at a time in a shared session, so the agent stays logged in between them. Reference an earlier step's output inside a later step's `input` with `{{ steps.<name>.output.<field> }}`. Add `if` to skip a step when a condition is false. Use a `for_each` step with `items` pointing at an array from an earlier step to run a task once per item, with `{{ item.<field> }}` for the current item.
Run with `POST /v2/workflows/{workflow_id}/run`, passing `credential_id` per step in a `steps` array. A workflow run (`wrun_`) stops on the first failed step and reports every step's status, output, and task runs. Subscribe to `workflow_run.completed` and `workflow_run.failed` rather than polling.
## Triggers
A trigger runs a task or a workflow on a cron schedule against a set of credentials, either an explicit `credential_ids` list or a `credential_filter` by source and status. Set exactly one of `task_id` / `workflow_id`. Each fire creates one task run, or one workflow run, per credential. Use `skip_if` to skip credentials whose last run already succeeded within a window.
## Events and Webhooks
Deck pushes events to destinations you configure (webhooks, AWS SQS, Kinesis, S3, GCP Pub/Sub, Azure Service Bus, RabbitMQ, Hookdeck).
Event format:
```json
{
"id": "evt_...",
"type": "task_run.completed",
"data": { ... },
"created_at": "2025-01-15T09:30:00Z"
}
```
Key event types:
- `credential.verified`, `credential.invalid`, `credential.deleted`
- `session.queued`, `session.running`, `session.idle`, `session.completing`, `session.completed`, `session.failed`
- `task_run.queued`, `task_run.running`, `task_run.pending`, `task_run.completed`, `task_run.failed`
- `task_run.interaction_required`
- `workflow_run.completed`, `workflow_run.failed`, `workflow_run.paused`
- `trigger_run.completed`, `trigger_run.failed`, `trigger.deactivated`
Webhook signatures follow the Standard Webhooks specification. Use the `standardwebhooks` SDK to verify with your `whsec_` signing secret.
## Pagination
All list endpoints use cursor-based pagination:
- Query params: `limit` (default 20, max 100), `cursor`
- Response: `{ "data": [...], "has_more": true, "next_cursor": "eyJ..." }`
- Loop until `has_more` is `false`
## Idempotency
All POST, PATCH, and DELETE endpoints accept an `Idempotency-Key` header (max 256 chars, expires after 24h). Same key + same params returns the original response. Same key + different params returns HTTP 409.
## Error Format
```json
{
"errors": [{ "type": "request", "code": "input_missing", "field": "name", "message": "..." }],
"request_id": "req_..."
}
```
Always branch on `type` and `code`, never on `message`. Always log `request_id` for debugging.
Common error codes:
- `rate_limit_exceeded` (429) - back off with exponential delay
- `auth_invalid` (401) - credentials are wrong
- `interaction_timeout` (408) - interaction expired, resubmit the task run
- `input_missing` (400) - check the `field` property
- `source_not_available` (503) - external website is down, retry later
- `idempotency_error` (409) - same key with different params
## CRITICAL RULES FOR AI MODELS
### Always do
1. Use event destinations (webhooks, queues) to receive results. Never poll.
2. Use `Idempotency-Key` on all create requests.
3. Handle `interaction_required` status on task runs.
4. Paginate with `cursor` and `has_more`, never offsets.
5. Verify webhook signatures using the Standard Webhooks SDK.
6. Handle errors by `type` and `code`, never by `message`.
7. Write task prompts as high-level, source-agnostic goals. A task runs across every source that supports it, so never reference a specific website or UI. The prompt is combined with Deck's agent harness, which handles navigation, authentication, and tool use. Example: "Log in and fetch the latest bill." not "Click the sign-in button, enter credentials, navigate to billing..."
8. Design task input schemas with only the fields that change between runs. Keep them source-agnostic. Do not add fields tied to a specific source.
9. Design task output schemas with generic fields any supporting source can populate. Optional fields return `null` when the source doesn't contain that information; if the source doesn't contain a `required` field, the run fails with a `task_not_supported` error. Do not mirror a single source's data model.
10. Reference task inputs by name in the prompt, never inline values: "Download bills between {start_date} and {end_date}".
11. Name agents and tasks after the use case, never after a source. An agent works across many sources: "Hotel Reservations", not "Hilton Reservations".
12. Chain dependent tasks with a workflow instead of orchestrating task runs from your server.
13. Schedule recurring runs across credentials with a trigger instead of your own cron. A trigger can target a workflow, so schedule the whole chain rather than its first task.
### Never do
1. Do not poll `/v2/task-runs/{id}` in a loop. Use events.
2. Do not hardcode source IDs. Create sources via the API or look them up.
3. Do not ignore `interaction_required`. Users may need to complete MFA.
4. Do not assume task runs complete synchronously. They are always async.
5. Do not send credentials from the client. Always proxy through your server.
6. Do not branch on error `message` strings. They can change without notice.
7. Do not include detailed navigation steps in task prompts. They conflict with the agent harness and can restrict tools the agent needs.
8. Do not add source-specific fields to task schemas. A task must work across all sources that support it.
9. Do not put credentials or login instructions in task prompts. Deck authenticates the session with the stored credential.
10. Do not put a source name in an agent or task name. Only sources are named after the site ("Hilton"); agents and tasks span sources.