# manifest.json

`manifest.json` is the integration registry for your Swytchcode project.

It stores metadata about every installed integration, including its version, API endpoints, authentication configuration, and execution behavior.

Unlike `tooling.json`, which defines **what can execute**, `manifest.json` defines **how an integration executes**.

The file is located at:

```
.swytchcode/integrations/manifest.json
```

Every integration installed using `swy get` or `swy add` automatically updates this file.

Both the CLI and the MCP server share this file during execution. Updates are serialized to prevent corruption when multiple tools modify it simultaneously.

---

## What does manifest.json do?

For every installed integration, Swytchcode stores:

- Integration version
- Sandbox endpoint
- Production endpoint
- Authentication metadata
- Method count
- Workflow count
- Execution policy

During execution, the kernel reads this file to determine:

1. Which endpoint should receive the request
2. How authentication should work
3. Whether retries are allowed
4. Timeout behavior
5. Idempotency settings
6. Concurrency limits

---

## File Structure

A simplified example looks like this:

```json
{
  "stripe.stripe": {
    "version": "v2",
    "sandbox_endpoint": "https://api.stripe.com",
    "production_endpoint": "https://api.stripe.com",
    "methods": 42,
    "workflows": 3,
    "auth": {
      "type": "api_key",
      "header": "Authorization"
    }
  }
}
```

Each top-level key represents a single integration.

---

## Entry Fields

Each integration contains the following fields.

### version

Defines the pinned version of the integration, e.g. `"v2"`. This is the same version string that appears next to the integration in `tooling.json.integrations` (for example `"stripe.stripe": { "version": "v2" }`) - the two files must agree, since `swy bootstrap` and `swy sync` compare them to decide what to fetch.

```json
{
  "version": "v2"
}
```

Swytchcode always executes using the pinned version stored in the manifest, never "whatever is newest." If you want a newer integration version, run `swy get <project>` again to fetch the new bundle and update this file - editing the field by hand won't fetch anything.

---

### sandbox_endpoint

Defines the base URL used when the project is running in sandbox mode (`tooling.json.mode: "sandbox"`).

```json
{
  "sandbox_endpoint": "https://sandbox.example.com"
}
```

Many providers (Stripe is a common example) use the same host for sandbox and production and distinguish environments by which API key you authenticate with instead of by URL - in that case `sandbox_endpoint` and `production_endpoint` are identical, as shown in the Complete Example below.

---

### production_endpoint

Defines the base URL used for production execution (`tooling.json.mode: "production"`).

```json
{
  "production_endpoint": "https://api.example.com"
}
```

Because the environment is resolved from `tooling.json.mode` rather than from a flag on `exec`, switching a project from sandbox to production means changing `mode` in `tooling.json` (or re-running `swy init --mode=production`) once, rather than remembering to pass an environment flag on every call.

---

### methods

Number of executable methods included in the integration bundle, e.g. `42`.

```json
{
  "methods": 42
}
```

This value is informational - it reflects what's available in the fetched bundle under `.swytchcode/integrations/`, not what's enabled in your project. Use `swy list tooling` to see what's actually been added via `swy add`, and `swy info <canonical_id>` to inspect one method in detail. It's maintained automatically by `swy get`, `swy bootstrap`, and `swy sync`; don't hand-edit it.

---

### workflows

Number of workflows provided by the integration, e.g. `5`.

```json
{
  "workflows": 5
}
```

Same caveat as `methods`: this counts what's in the bundle, not what's registered in `tooling.json.tools`. Run `swy add workflow <canonical_id>` to actually enable one.

---

### auth

Authentication metadata used by Swytchcode to know *how* to authenticate against this provider - it's the schema, not the secret. The actual key or token is never stored here; it's resolved separately at execution time (see [Managed Authentication](/guides/managed-authentication/)).

Example:

```json
{
  "auth": {
    "type": "api_key",
    "header": "Authorization"
  }
}
```

Depending on the integration, authentication metadata may include:

- Authentication type (`api_key` or `oauth`)
- OAuth scopes
- Authorization header name
- Token format

`swy auth connect [provider]` reads this block to decide whether to prompt for an API key or start an OAuth flow, and `swy auth connect` with no argument reads it across every installed integration to list which providers still need credentials. `swy doctor` also checks this block as part of validating that installed integrations are fully configured.

---

### execution_policy

Defines how HTTP requests to this integration behave: retries, timeouts, concurrency, response-size limits, and idempotency. Every field is optional and unset fields fall back to the built-in defaults - see the full [Execution Policy](#execution-policy) breakdown below for every field, its default, and when to change it.

---

## Environment Selection

Swytchcode automatically chooses the correct endpoint using the project mode defined in `tooling.json`.

```
tooling.json

mode = sandbox
        │
        ▼
sandbox_endpoint
```

```
tooling.json

mode = production
        │
        ▼
production_endpoint
```

The final request URL is built as:

```
Base URL
      +
Method Endpoint
      =
Final Request URL
```

For example:

```
https://api.stripe.com
                +
/v1/customers
                =
https://api.stripe.com/v1/customers
```

Whenever a request executes, Swytchcode prints the active environment.

Example:

```
Running live - stripe (production)
```

This prevents accidental production requests.

If you're not sure an endpoint is reachable before you run a real workflow against it, `swy doctor --network` checks every configured endpoint (sandbox and production, across all installed integrations) and reports its current status.

---

## URL Security Rules

Swytchcode enforces URL safety automatically.

### HTTPS

HTTPS is supported for every host.

```
https://api.stripe.com
```

---

### HTTP

HTTP is only allowed for local development.

Supported hosts:

- localhost
- 127.0.0.1
- ::1

Requests to external HTTP endpoints are rejected.

---

### Self-signed certificates

For local development, TLS verification can be disabled.

```bash
SWYTCHCODE_INSECURE=1
```

This is only allowed outside CI environments.

When running in GitHub Actions, GitLab CI, or other supported CI environments, insecure TLS is always rejected.

---

## Execution Policy

The `execution_policy` object controls how HTTP requests are executed for a single integration: retry attempts, retry delays, timeouts, concurrency, response-size limits, and idempotency. It lives inside that integration's entry in `manifest.json`, so different integrations can have different policies - a flaky third-party API might get a higher `max_retries` while an internal service you fully trust gets none.

Every field is optional. You only need to set the fields you want to override; Swytchcode merges the rest with its built-in defaults (documented field-by-field below).

Example - retry more aggressively and allow more time per request for a slow provider:

```json
{
  "execution_policy": {
    "max_retries": 5,
    "http_timeout_ms": 60000
  }
}
```

---

## Retry Configuration

### max_retries

Maximum retry attempts after the first request.

Default:

```json
3
```

Negative values are treated as `0`.

---

### retry_on

HTTP status codes that trigger retries.

Default:

```json
[
  429,
  503,
  504
]
```

---

### non_retryable

Status codes that are never retried.

Default:

```json
[
  400,
  401,
  403,
  404,
  422
]
```

---

### on_401

Determines what happens when authentication fails.

Supported values:

| Value | Description |
|--------|-------------|
| `fail` | Immediately fail the request. |
| `refresh_and_retry` | Refresh OAuth credentials once and retry. |

Default:

```json
{
  "on_401": "fail"
}
```

---

## Retry Delays

### base_delay_ms

Initial retry delay.

Default:

```json
500
```

(milliseconds)

---

### max_delay_ms

Maximum retry delay.

Default:

```json
30000
```

(milliseconds)

---

## Timeouts

### connect_timeout_ms

Maximum DNS and TCP connection time.

Default:

```json
5000
```

---

### http_timeout_ms

Maximum duration for an individual request.

Default:

```json
30000
```

---

### total_timeout_ms

Maximum duration including all retries.

Default:

```json
90000
```

---

## Concurrency

### max_concurrent

Limits parallel requests to a provider.

Default:

```json
5
```

Setting the value to `0` or a negative number disables the limiter.

---

## Response Size

### max_response_bytes

Maximum response size before truncation.

Default:

```json
102400
```

(bytes)

Values less than or equal to zero disable response truncation.

---

## Idempotency

Mutating APIs sometimes receive duplicate requests due to retries or network failures.

The `idempotency` object prevents duplicate operations by attaching an idempotency key.

Example:

```json
{
  "idempotency": {
    "mode": "dynamic",
    "scope": "workflow"
  }
}
```

---

### mode

Determines whether idempotency is enabled.

| Value | Description |
|--------|-------------|
| `none` | Disable idempotency. |
| `dynamic` | Automatically attach an idempotency key. |

Default:

```json
none
```

---

### header_name

Header used for the idempotency key.

Default:

```json
Idempotency-Key
```

---

### scope

Determines how keys are generated.

| Value | Description |
|--------|-------------|
| `call` | New key for every request. |
| `workflow` | Stable key across workflow execution. |

---

## Complete Example

```json
{
  "stripe.stripe": {
    "version": "v2",
    "sandbox_endpoint": "https://api.stripe.com",
    "production_endpoint": "https://api.stripe.com",
    "methods": 42,
    "workflows": 3,
    "auth": {
      "type": "api_key",
      "header": "Authorization"
    },
    "execution_policy": {
      "max_retries": 5,
      "on_401": "refresh_and_retry",
      "max_concurrent": 3,
      "idempotency": {
        "mode": "dynamic",
        "scope": "workflow"
      }
    }
  }
}
```

---

## How manifest.json Fits into Execution

Every API execution follows the same flow.

```
tooling.json
      │
      │  Is this tool trusted?
      ▼

policies.json
      │
      │  Is this request allowed?
      ▼

manifest.json
      │
      │  Which endpoint?
      │  Which auth?
      │  Retry policy?
      │  Timeout?
      │  Idempotency?
      ▼

Execute API Request
```

`tooling.json` defines **what** can execute.

`policies.json` defines **whether** it should execute.

`manifest.json` defines **how** it executes.

Together, these three files form the core execution model of Swytchcode.

---

## Best Practices

- Do not edit generated values unless necessary.
- Commit `manifest.json` to version control.
- Keep integration versions pinned.
- Prefer sandbox mode during development.
- Configure retries based on the API provider.
- Enable idempotency for mutating operations.
- Review timeout settings for long-running APIs.

---

Continue learning about the execution pipeline:

## Next Steps

- [Execution Pipeline](https://docs.swytchcode.com/guides/execution-pipeline/) - Understand how Swytchcode combines tooling.json, policies.json, and manifest.json during every API request.
- [tooling.json](https://docs.swytchcode.com/configuration/tooling-json/) - Learn how trusted tools are defined.
- [policies.json](https://docs.swytchcode.com/configuration/policy-json/) - Learn how runtime guard policies validate requests before execution.
