# Organization Payment Config

This document describes the MCP tools for managing organization payment configurations in Airbyte Cloud. These tools enable reading and updating billing state for organizations, including grace period management.

## Overview

The payment config tools provide two operations:

- **`get_organization_payment_config`** (read-only): Retrieve the current payment status, subscription status, grace period, and usage category for an organization. No PII or sensitive payment details are returned.
- **`update_organization_payment_config`** (destructive): Set or modify grace periods and/or usage category overrides for an organization. Requires [human-in-the-loop approval](#authorization).

## Payment Status State Machine

Organizations have a `payment_status` that follows this state machine:

| Status | Description | Set By |
|--------|-------------|--------|
| `uninitialized` | Default state; customer has not set up billing | Billing automation only |
| `okay` | Billing is healthy; payments are current | Billing automation only |
| `grace_period` | Payment failed; temporary reprieve before disabling | API (from `manual` only) |
| `disabled` | Grace period expired; connections are disabled | Billing automation only |
| `locked` | Manually locked; all connections disabled | API (from any status) |
| `manual` | Manually managed billing; Stripe webhooks are ignored | API (from any status) |

The API only allows setting status to `grace_period` (from `manual`), `manual` (from any), or `locked` (from any). The statuses `uninitialized`, `okay`, and `disabled` are controlled exclusively by billing automation (Stripe/Orb webhooks).

## MCP Tool: `get_organization_payment_config`

### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `organization_id` | string | Yes | -- | The organization UUID |
| `config_api_root` | string | No | `https://cloud.airbyte.com/api/v1` | Config API root URL override |

### Return Value

Returns an `OrganizationPaymentConfigInfo` object with:

- `organization_id`: The organization UUID
- `payment_status`: Current payment status enum value
- `subscription_status`: One of `pre_subscription`, `subscribed`, `unsubscribed`
- `payment_provider_id`: Stripe customer ID (opaque reference, not a payment method)
- `grace_period_end_at`: ISO 8601 datetime if a grace period is active
- `usage_category_overwrite`: `free` or `internal` if set
- `customer_tier`: Tier classification (`TIER_0`, `TIER_1`, or `TIER_2`)
- `tier_warning`: Warning message for sensitive customer tiers (TIER_0/TIER_1)

## MCP Tool: `update_organization_payment_config`

### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `organization_id` | string | Yes | -- | The organization UUID |
| `approval_comment_url` | string | Yes | -- | Slack approval record URL from `escalate_to_human` |
| `organization_name` | string | Effectively yes | `None` | Safety check: org name, email, or email domain. Optional in schema but the tool fails fast with valid identifiers if omitted or mismatched |
| `set_grace_period` | string | No | `None` | Grace period action (see [Grace Period Actions](#grace-period-actions)). Mutually exclusive with `set_permanent_waiver_type` |
| `set_grace_period_reason` | string | No | `None` | Reason for the grace period change. Required when setting/extending |
| `set_permanent_waiver_type` | string | No | `None` | Permanent billing waiver: `free` (partner/non-paying), `internal` (Airbyte-internal), or `none` (remove waiver). Mutually exclusive with `set_grace_period`. See [Permanent Waiver Type](#permanent-waiver-type) |
| `set_permanent_waiver_reason` | string | No | `None` | Reason for setting the permanent billing waiver. Required when `set_permanent_waiver_type` is provided |
| `config_api_root` | string | No | `https://cloud.airbyte.com/api/v1` | Config API root URL override |

### Grace Period Actions

The `set_grace_period` parameter accepts three forms:

| Input | Example | Behavior |
|-------|---------|----------|
| Date (`YYYY-MM-DD`) | `"2026-05-15"` | Sets grace period end to 11:59 PM Pacific on that date |
| Integer (days) | `"14"` | Sets grace period end to 11:59 PM Pacific, N days from today (Pacific Time) |
| `"cancel"` | `"cancel"` | Terminates the current grace period (sets status to `manual`) |

### Return Value

Returns an `OrganizationPaymentConfigUpdateResult` object with:

- `success`: Whether the update completed successfully
- `message`: Human-readable description of the outcome
- `organization_id`: The organization UUID
- `payment_status`: The resulting payment status after the update
- `grace_period_end_at`: The grace period end date if applicable
- `permanent_waiver_type`: The permanent billing waiver after the update (`free`, `internal`, or `None`)
- `customer_tier`: Tier classification
- `tier_warning`: Warning message for sensitive tiers

### Organization Name Validation

The `organization_name` parameter is a safety check to prevent accidental modifications to the wrong organization. The tool looks up the organization via the Config API and verifies the input against:

- The organization's literal name (e.g., `"Acme Corp"`)
- The organization's email address (e.g., `"billing@acme.com"`)
- The organization's email domain (e.g., `"acme.com"`)

If `organization_name` is omitted or does not match any of the above, the tool returns an error with all valid identifiers so the caller can verify and retry. The error message instructs the agent to confirm with its user if there is any doubt.

## Authorization

All calls to `update_organization_payment_config` require human-in-the-loop approval:

1. **Call `escalate_to_human`** with `approval_requested=True` and a summary of the planned action
2. **Wait for approval** — a human clicks "Approve" in the `#human-in-the-loop` Slack channel
3. **Pass the approval record URL** as `approval_comment_url` to the update tool

Additionally, the `AIRBYTE_INTERNAL_ADMIN_FLAG=airbyte.io` environment variable must be set.

## Grace Period Workflow

### Setting a Grace Period

To set a grace period for an organization (e.g., extending access for a customer with a billing issue):

```bash
# Step 1: Verify current status
poe mcp-tool-test get_organization_payment_config '{
  "organization_id": "<org-uuid>"
}'

# Step 2: Set the grace period (requires prior escalate_to_human approval)
poe mcp-tool-test update_organization_payment_config '{
  "organization_id": "<org-uuid>",
  "organization_name": "<org-name-or-email-or-domain>",
  "approval_comment_url": "<slack-approval-url>",
  "set_grace_period": "2026-05-15",
  "set_grace_period_reason": "Grace period extension per #ask-finance request"
}'
```

If the organization is not already in `manual` status, the tool automatically transitions to `manual` first before setting the grace period. See [Known Limitations](#known-limitations) for risks associated with this two-step process.

### Grace Period Lifecycle

Once a grace period is active:

- **Customer pays before the end date** → Stripe webhook transitions the org to `okay` and terminates the grace period
- **End date is reached without payment** → A Temporal workflow timer fires and transitions the org to `disabled`, disabling all connections

### Canceling a Grace Period

```bash
poe mcp-tool-test update_organization_payment_config '{
  "organization_id": "<org-uuid>",
  "organization_name": "<org-name>",
  "approval_comment_url": "<slack-approval-url>",
  "set_grace_period": "cancel",
  "set_grace_period_reason": "Grace period no longer needed"
}'
```

This sets the organization to `manual` status, terminating the grace period.

## Permanent Waiver Type

The `set_permanent_waiver_type` parameter sets a permanent billing waiver for an organization:

| Value | Description | Use Case |
|-------|-------------|----------|
| `free` | Non-paying account; usage is not billed | Partner accounts, sponsored accounts |
| `internal` | Airbyte-internal account | Internal testing, dogfooding |
| `none` | Remove an existing waiver | Reverting a partner/internal designation |

This is mutually exclusive with `set_grace_period` — only one may be provided per call:

```bash
# Mark an org as a partner (non-paying) account
poe mcp-tool-test update_organization_payment_config '{
  "organization_id": "<org-uuid>",
  "organization_name": "<org-name-or-email-or-domain>",
  "approval_comment_url": "<slack-approval-url>",
  "set_permanent_waiver_type": "free",
  "set_permanent_waiver_reason": "Partner account per #ask-finance approval"
}'
```

## Known Limitations

### Two-Step Grace Period Transition ([#749](https://github.com/airbytehq/airbyte-ops-mcp/issues/749))

The Airbyte Cloud Config API only allows setting `grace_period` from `manual` status. For organizations in any other status (e.g., `disabled`), the tool must perform two sequential API calls:

1. Set status to `manual`
2. Set status to `grace_period` with the end date

If step 1 succeeds but step 2 fails (network error, validation rejection, etc.), the organization is left in `manual` status. In `manual` status, Stripe webhooks are ignored, meaning billing automation is bypassed until the status is corrected.

The tool reports this partial failure explicitly in its response, indicating the organization is now in `manual` status and prompting corrective action. However, the underlying risk should be addressed by the backend team by allowing direct `grace_period` transitions from any status.

## Related Resources

- [Customer Tiers](./customer-tiers.md) — tier classification and tier-aware tool behavior
- [Issue #749](https://github.com/airbytehq/airbyte-ops-mcp/issues/749) — tracking the two-step transition risk
