{
  "openapi": "3.1.0",
  "info": {
    "title": "Tenure Retention API",
    "version": "1.1.0",
    "summary": "Recommend/Enable retention offers from any AI support agent.",
    "description": "Tenure decides, per customer, whether to make a save attempt and with which single approved offer. AI agents (Intercom Fin, Decagon, Sierra, Zendesk AI, custom MCP/REST clients) call **Recommend** when a customer wants to cancel and **Enable** when they say yes or no; Tenure executes the billing change with guardrails intact.\n\n**Auth**: `Authorization: Bearer <api key>` (or `x-api-key`). Keys carry scopes (`read`, `decide`, `draft_write`; none of them publishes: publishing, enabling and approving need a signed-in person), may expire, and may be test keys (every session they create is test mode: nothing bills).\n**Errors**: every non-2xx body is `{ \"error\": { \"code\", \"message\", \"ref\"? } }`. `code` is stable and documented under `components.schemas.Error`.\n**Session chain**: send your own conversation id as `X-Session-Id` on every call and the whole conversation lands on one Tenure session: `POST /subscriptions/{id}/recommended-offer` → `POST /offers/{id}/apply` or `/decline` → `POST /subscriptions/{id}/cancel` → `POST /sessions/{id}/end`. The header follows the session when a new recommendation supersedes it, and `POST /recommend` and `POST /enable` accept it too.\n**Idempotency**: send `Idempotency-Key` on POST /recommend, /enable and /subscriptions/{id}/recommended-offer.\n**MCP**: the same operations are exposed as MCP tools at `POST /api/mcp` (`?profile=agent` for the customer-facing subset). Tool manifest: `GET /api/v1/tools`.\n**Docs**: every developer page is served as Markdown. Index: https://app.trytenure.co/docs. For agents: https://app.trytenure.co/llms.txt (one line per page) and https://app.trytenure.co/llms-full.txt (every page in one file)."
  },
  "servers": [
    {
      "url": "https://app.trytenure.co"
    }
  ],
  "tags": [
    {
      "name": "Agent",
      "description": "What an AI support agent calls during a cancellation conversation."
    },
    {
      "name": "Data",
      "description": "Keep Tenure's customer data and signals current."
    },
    {
      "name": "Compliance"
    },
    {
      "name": "Public"
    },
    {
      "name": "Auth"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "ck_live_... API key",
        "description": "Create keys in Settings. Also accepted as `x-api-key`."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    },
    "schemas": {
      "TelemetryHeartbeatRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "sourceKey",
          "sequence",
          "observedAt",
          "status",
          "cadenceSeconds"
        ],
        "properties": {
          "sourceKey": {
            "type": "string",
            "maxLength": 180,
            "pattern": "^(product-events|event:[a-z][a-z0-9_]{2,47}|(?:customer_data|usage):[a-zA-Z0-9_-]+)$",
            "description": "product-events covers the direct host stream; event:<technicalName> requires a current confirmed enabled event fact. customer_data:<sourceId> and usage:<sourceId> must belong to this workspace and the authenticated environment."
          },
          "sequence": {
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991,
            "description": "Durable increasing counter per source and environment; preserve it across sender restarts. Only an identical latest sequence and payload is an idempotent replay."
          },
          "observedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the independent server health check. New sequences must advance observation time. Future skew above 15 seconds is rejected; accepted future skew never extends the deadline past server receipt plus three cadences."
          },
          "status": {
            "type": "string",
            "enum": [
              "healthy",
              "degraded",
              "down"
            ]
          },
          "cadenceSeconds": {
            "type": "integer",
            "minimum": 30,
            "maximum": 3600,
            "description": "Expected cadence, fixed on first enrollment. Health expires exactly three cadences after the observation, bounded by receipt time."
          }
        }
      },
      "TelemetryHeartbeatResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "accepted",
          "duplicate",
          "freshUntil",
          "version"
        ],
        "properties": {
          "accepted": {
            "type": "boolean",
            "const": true,
            "description": "The report was recorded; this does not authorize a proactive action."
          },
          "duplicate": {
            "type": "boolean",
            "description": "An identical replay; freshness was not extended."
          },
          "freshUntil": {
            "type": "string",
            "format": "date-time"
          },
          "version": {
            "type": "string",
            "description": "Opaque health generation, stable during continuous healthy cadence and changed by negative health or a missed heartbeat window."
          }
        }
      },
      "SessionBlock": {
        "type": "object",
        "description": "The session block: one serializer for webhooks, the Sessions API, MCP and DSR.",
        "properties": {
          "subscriptionAtSession": {
            "type": "object",
            "description": "Immutable known subscription facts captured when the session was created. Legacy or unknown fields are null; customer remains the current record.",
            "properties": {
              "capturedAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "trial": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "billingInterval": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "planId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "plan": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "currency": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "id": {
            "type": "string"
          },
          "result": {
            "type": "string",
            "enum": [
              "saved",
              "not_applied",
              "cancelled",
              "abandoned",
              "superseded",
              "expired",
              "escalated",
              "open"
            ],
            "description": "saved = accepted and applied; not_applied = accepted but billing never carried it out; cancelled = the cancellation was confirmed (declining the offer included)"
          },
          "status": {
            "type": "string"
          },
          "executionStatus": {
            "type": "string",
            "description": "DONE, HOST (applied by your app), UNAPPLIED (no billing connected), FAILED, NONE, RESERVED"
          },
          "applied": {
            "type": "boolean"
          },
          "appliedBy": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "tenure",
              "host",
              null
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ]
          },
          "surface": {
            "type": "string"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "reasonText": {
            "type": [
              "string",
              "null"
            ]
          },
          "followup": {
            "type": [
              "string",
              "null"
            ],
            "description": "Label of the follow-up option picked."
          },
          "followupId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Its stable id."
          },
          "followupText": {
            "type": [
              "string",
              "null"
            ],
            "description": "What they typed in the follow-up box."
          },
          "usedClickToCancel": {
            "type": "boolean"
          },
          "region": {
            "type": [
              "string",
              "null"
            ],
            "description": "US-CA or DE"
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "Language the flow was shown in"
          },
          "browserLanguage": {
            "type": [
              "string",
              "null"
            ]
          },
          "bounced": {
            "type": "boolean"
          },
          "variant": {
            "type": "string"
          },
          "arm": {
            "type": "string"
          },
          "presentedOffers": {
            "type": "array",
            "description": "The published alternative the customer saw (one per attempt), with when it was declined.",
            "items": {
              "type": "object",
              "properties": {
                "rowId": {
                  "type": "string"
                },
                "kind": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "termsRef": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "presentedAt": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                },
                "acceptedAt": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "declinedAt": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "acceptedOffer": {
            "$ref": "#/components/schemas/OfferTerms"
          },
          "savedMrrCents": {
            "type": "integer",
            "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "resolvedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updatedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "CustomerBlock": {
        "type": "object",
        "description": "Synced snapshot of the subscriber.",
        "properties": {
          "externalId": {
            "type": "string"
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "plan": {
            "type": "string"
          },
          "mrrCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Monthly-equivalent app cents in currency. Null means unreported or incompatible workspace currency; zero means explicitly reported zero."
          },
          "currency": {
            "type": "string"
          },
          "billingInterval": {
            "type": [
              "string",
              "null"
            ]
          },
          "trial": {
            "type": "boolean"
          },
          "trialEndsAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "status": {
            "type": "string"
          },
          "tenureMonths": {
            "type": "number"
          },
          "subscriptionId": {
            "type": [
              "string",
              "null"
            ]
          },
          "subscriptionStartedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "currentPeriodEndsAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "provider": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "stripe",
              "chargebee",
              null
            ]
          },
          "providerCustomerId": {
            "type": [
              "string",
              "null"
            ]
          },
          "attributes": {
            "type": "object",
            "additionalProperties": true,
            "description": "Custom attributes; registered ones typed (number, boolean, ISO date)."
          }
        }
      },
      "OfferTerms": {
        "type": [
          "object",
          "null"
        ],
        "description": "The published row the session presented, with its terms body exactly as published.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The published row id."
          },
          "kind": {
            "type": "string",
            "description": "pause, discount, downgrade, extension, credit, talk_to_founder…"
          },
          "terms": {
            "type": "object",
            "description": "The row's terms: pause {days, options?}, discount {percent | amountCents, months}, downgrade {planId, priceId, newPriceCents, loses?, starts?} (starts: renewal means the plan changes when the current billing period ends), extension {days}…"
          },
          "currency": {
            "type": "string"
          },
          "pauseResumesAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Provider-confirmed historical restart date; null without immutable session-scoped evidence."
          },
          "selectedPauseDays": {
            "type": [
              "number",
              "null"
            ],
            "description": "Requested pause duration including the customer choice; does not confirm a billing restart date."
          },
          "schedule": {
            "type": "string",
            "enum": [
              "immediate",
              "end_of_period"
            ]
          },
          "prorate": {
            "type": "boolean"
          }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "required": [
          "event",
          "eventId",
          "createdAt",
          "v"
        ],
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "session.completed",
              "offer.accepted",
              "usage.grant",
              "cancel.confirmed",
              "session.escalated",
              "subscription.resumed",
              "refund.completed",
              "test.ping"
            ]
          },
          "eventId": {
            "type": "string",
            "description": "Stable across retries."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "v": {
            "type": "integer",
            "const": 2
          },
          "sessionId": {
            "type": "string"
          },
          "customerId": {
            "type": "string"
          },
          "result": {
            "type": "string",
            "description": "session.completed: same as session.result"
          },
          "session": {
            "$ref": "#/components/schemas/SessionBlock"
          },
          "customer": {
            "$ref": "#/components/schemas/CustomerBlock"
          },
          "offerTerms": {
            "$ref": "#/components/schemas/OfferTerms"
          },
          "grant": {
            "type": "object",
            "description": "usage.grant: the units to add. Acknowledge with { ok: true, grantId }.",
            "properties": {
              "grantId": {
                "type": "string",
                "description": "The acceptance; stable across retries. Add the units once per grantId."
              },
              "unit": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The count's technical name."
              },
              "units": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "expiresAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "customerId": {
                "type": "string"
              },
              "subscriptionId": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "test": {
            "type": "boolean",
            "description": "usage.grant: true on the Send a test grant request (customerId tenure_test_customer)."
          },
          "offer": {
            "type": "object",
            "description": "offer.accepted (and usage.grant: id, kind, termsRef): the published row accepted. A credit sized to the customer and extra usage have the derived id `<rowId>~<n>` (n: the amount in minor units, or the units), terms for that one amount, and a null label.",
            "properties": {
              "id": {
                "type": "string"
              },
              "kind": {
                "type": "string"
              },
              "label": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "termsRef": {
                "type": "string"
              },
              "terms": {
                "type": "object",
                "additionalProperties": true
              },
              "currency": {
                "type": "string"
              }
            }
          },
          "environment": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ],
            "description": "offer.accepted, usage.grant: the acceptance's environment."
          },
          "moment": {
            "type": "object",
            "description": "offer.accepted: the moment the offer was accepted in.",
            "properties": {
              "id": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "enum": [
                  "cancel_click",
                  "trial_ending",
                  "limit_reached",
                  "gated_feature",
                  "cost_exceeds_price",
                  "going_quiet",
                  "cancelled"
                ]
              },
              "surface": {
                "type": "string"
              },
              "sessionId": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "execution": {
            "type": "object",
            "description": "offer.accepted: the billing change and its outcome when sent.",
            "properties": {
              "id": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "awaiting_confirmation",
                  "failed",
                  "simulated"
                ]
              },
              "action": {
                "type": "string"
              },
              "provider": {
                "type": "string"
              },
              "reference": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "acceptedBy": {
                "type": "string",
                "enum": [
                  "customer",
                  "founder"
                ]
              },
              "acceptedAt": {
                "type": "string",
                "format": "date-time"
              },
              "confirmedAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          },
          "reason": {
            "type": [
              "object",
              "null"
            ],
            "description": "offer.accepted, cancel clicks: the picked reason and the customer's typed text, minimised.",
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "text": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "refund": {
            "$ref": "#/components/schemas/Refund"
          }
        },
        "additionalProperties": true
      },
      "Offer": {
        "type": "object",
        "nullable": true,
        "description": "The single approved offer. Never improvise beyond it.",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "DISCOUNT",
              "PAUSE",
              "DOWNGRADE",
              "PLAN_CHANGE",
              "TRIAL_EXTENSION",
              "TERM_EXTENSION",
              "REBATE",
              "CONTACT",
              "MONTHLY_SWITCH",
              "REFUND_NOW"
            ]
          },
          "headline": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "ctaLabel": {
            "type": "string"
          },
          "discountPercent": {
            "type": [
              "number",
              "null"
            ],
            "description": "Null when the offer uses a fixed amount instead."
          },
          "discountAmountCents": {
            "type": [
              "number",
              "null"
            ],
            "description": "Fixed amount off in minor units; mutually exclusive with discountPercent."
          },
          "discountMonths": {
            "type": [
              "number",
              "null"
            ]
          },
          "pauseDays": {
            "type": [
              "number",
              "null"
            ]
          },
          "pauseOptions": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "targetPlan": {
            "type": [
              "string",
              "null"
            ]
          },
          "planNickname": {
            "type": [
              "string",
              "null"
            ],
            "description": "PLAN_CHANGE/DOWNGRADE display name for the target plan."
          },
          "planTagline": {
            "type": [
              "string",
              "null"
            ]
          },
          "planFeatures": {
            "type": "array",
            "maxItems": 4,
            "items": {
              "type": "string"
            }
          },
          "comparison": {
            "type": [
              "object",
              "null"
            ],
            "description": "Current plan vs target plan, for a two-column display.",
            "additionalProperties": true
          },
          "extensionDays": {
            "type": [
              "number",
              "null"
            ]
          },
          "preview": {
            "type": "object",
            "properties": {
              "lines": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "additionalProperties": true
          }
        }
      },
      "Traits": {
        "type": "object",
        "description": "Optional customer attributes to upsert (plan, mrrCents, tenureMonths, attributes...).",
        "additionalProperties": true
      },
      "Customer": {
        "type": "object",
        "required": [
          "externalId"
        ],
        "properties": {
          "externalId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 120
          },
          "plan": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "cancelled"
            ]
          },
          "mrrCents": {
            "type": "integer",
            "minimum": 0,
            "maximum": 2147483647
          },
          "ltvCents": {
            "type": "integer",
            "minimum": 0,
            "maximum": 2147483647,
            "description": "What Tenure has recorded them paying, in cents net of refunds: invoices its billing webhook saw since it connected, or a total an import or the Customers API supplied. Payments from before Tenure are missing unless supplied, so this is not a lifetime value."
          },
          "tenureMonths": {
            "type": "number",
            "minimum": 0
          },
          "usageTrend": {
            "type": [
              "number",
              "null"
            ],
            "minimum": -1,
            "maximum": 1
          },
          "promo": {
            "type": "boolean"
          },
          "trial": {
            "type": "boolean"
          },
          "billingInterval": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "day",
              "week",
              "month",
              "year",
              null
            ]
          },
          "billingIntervalCount": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "maximum": 365,
            "description": "How many billing intervals one invoice covers: 3 with billingInterval \"month\" is a quarterly plan. Offers are costed against that invoice."
          },
          "subscriptionStartedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "trialEndsAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "currentPeriodEndsAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "lastActiveAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "stripeCustomerId": {
            "type": [
              "string",
              "null"
            ]
          },
          "stripeSubscriptionId": {
            "type": [
              "string",
              "null"
            ]
          },
          "chargebeeCustomerId": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1,
            "maxLength": 200
          },
          "chargebeeSubscriptionId": {
            "type": [
              "string",
              "null"
            ]
          },
          "attributes": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "Session": {
        "type": "object",
        "description": "A cancel session (full record).",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "executionStatus": {
            "type": "string"
          },
          "surface": {
            "type": "string"
          },
          "platform": {
            "type": [
              "string",
              "null"
            ]
          },
          "conversationId": {
            "type": [
              "string",
              "null"
            ]
          },
          "isTest": {
            "type": "boolean"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "arm": {
            "type": "string"
          },
          "executionLog": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "savedMrrCents": {
            "type": "integer",
            "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "resolvedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "additionalProperties": true
      },
      "SessionSummary": {
        "type": "object",
        "description": "One row of GET /api/v1/sessions: the original summary keys plus every SessionBlock field and the `customer` block.",
        "allOf": [
          {
            "$ref": "#/components/schemas/SessionBlock"
          }
        ],
        "properties": {
          "customer": {
            "$ref": "#/components/schemas/CustomerBlock"
          },
          "id": {
            "type": "string"
          },
          "customerId": {
            "type": "string"
          },
          "customerEmail": {
            "type": [
              "string",
              "null"
            ]
          },
          "plan": {
            "type": "string"
          },
          "surface": {
            "type": "string"
          },
          "isTest": {
            "type": "boolean"
          },
          "status": {
            "type": "string"
          },
          "executionStatus": {
            "type": "string"
          },
          "arm": {
            "type": "string"
          },
          "variant": {
            "type": "string"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "reasonText": {
            "type": [
              "string",
              "null"
            ],
            "description": "What the customer typed in the free-text box, minimised before it was stored: emails, links, phone numbers, long numbers and names are replaced with [email], [link], [phone], [number] and [name]. The raw words are never stored."
          },
          "bounced": {
            "type": "boolean",
            "description": "Closed within seconds without an interaction."
          },
          "offer": {
            "type": [
              "object",
              "null"
            ],
            "description": "The published row the session presented.",
            "properties": {
              "id": {
                "type": "string"
              },
              "kind": {
                "type": "string"
              }
            }
          },
          "presentedOffers": {
            "type": "array",
            "description": "The published alternative the customer saw (one per attempt), with when it was declined.",
            "items": {
              "type": "object",
              "properties": {
                "rowId": {
                  "type": "string"
                },
                "kind": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "termsRef": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "presentedAt": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                },
                "acceptedAt": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "declinedAt": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "savedMrrCents": {
            "type": "integer",
            "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "resolvedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "SessionList": {
        "type": "object",
        "required": [
          "sessions",
          "hasMore"
        ],
        "properties": {
          "sessions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionSummary"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass back as `cursor` for the next page; null on the last page."
          },
          "hasMore": {
            "type": "boolean"
          }
        }
      },
      "RecommendRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "customerId": {
            "type": "string",
            "maxLength": 200,
            "description": "Your subscriber id. Required unless email is given (or X-Session-Id names a session)."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "traits": {
            "$ref": "#/components/schemas/Traits"
          },
          "reason": {
            "type": "string",
            "maxLength": 64,
            "description": "A reason id from your published Cancellations plan; an unknown id is recorded as other."
          },
          "conversation": {
            "type": "string",
            "maxLength": 4000,
            "description": "The subscriber's own words. Read as data, never as instructions; the last 1,200 characters are sent to the decision."
          },
          "subscriptionId": {
            "type": "string",
            "maxLength": 200,
            "description": "Which of the customer's subscriptions this is about. Must be on their record; billing changes target it."
          },
          "language": {
            "type": "string",
            "maxLength": 12,
            "description": "Copy language (BCP-47); the publication's first language when it has no copy in this one."
          },
          "mode": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ],
            "description": "test records a test attempt. Test API keys force this."
          },
          "platform": {
            "type": "string",
            "maxLength": 60,
            "description": "Calling platform, e.g. intercom_fin, decagon, sierra, zendesk. Stored on the session."
          },
          "conversationId": {
            "type": "string",
            "maxLength": 200,
            "description": "Your conversation/ticket id, for tracing."
          },
          "externalSessionId": {
            "type": "string",
            "maxLength": 200,
            "description": "Your conversation id. Normally sent as the `X-Session-Id` header instead; the header wins."
          }
        }
      },
      "RecommendResponse": {
        "type": "object",
        "required": [
          "decision",
          "sessionId",
          "deliveryId",
          "environment",
          "isTest",
          "offer",
          "compliance",
          "nextStep"
        ],
        "properties": {
          "decision": {
            "type": "string",
            "enum": [
              "offer",
              "nothing"
            ],
            "description": "offer: render exactly this one offer beside a way to cancel. nothing: offer nothing and let them cancel."
          },
          "sessionId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Null only with fallbackReason engine_error: no attempt could be recorded."
          },
          "deliveryId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Report what the subscriber saw: POST /api/v1/deliveries/{deliveryId}/report."
          },
          "momentId": {
            "type": [
              "string",
              "null"
            ]
          },
          "decisionId": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "executionStatus": {
            "type": [
              "string",
              "null"
            ]
          },
          "environment": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ]
          },
          "isTest": {
            "type": "boolean"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "language": {
            "type": [
              "string",
              "null"
            ]
          },
          "offer": {
            "type": [
              "object",
              "null"
            ],
            "description": "One approved alternative from the published plan, in its reviewed words.",
            "properties": {
              "id": {
                "type": "string"
              },
              "kind": {
                "type": "string"
              },
              "headline": {
                "type": "string"
              },
              "body": {
                "type": "string"
              },
              "ctaLabel": {
                "type": "string"
              },
              "changes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "effect": {
                "type": "object",
                "additionalProperties": true
              }
            }
          },
          "fallbackReason": {
            "type": "string",
            "enum": [
              "timeout",
              "error",
              "no_key",
              "refused",
              "incomplete",
              "deadline_too_short",
              "engine_error"
            ],
            "description": "The decision could not be made in time or at all; the answer is nothing."
          },
          "preview": {
            "type": "boolean",
            "const": true,
            "description": "The plan is Preview only: the attempt was recorded with what would have been offered; nothing is shown."
          },
          "compliance": {
            "type": "object",
            "properties": {
              "exitRequired": {
                "type": "boolean",
                "const": true
              },
              "oneOfferMax": {
                "type": "boolean",
                "const": true
              },
              "environment": {
                "type": "string",
                "enum": [
                  "live",
                  "test"
                ]
              }
            }
          },
          "externalSessionId": {
            "type": "string"
          },
          "nextStep": {
            "type": "string"
          }
        }
      },
      "DeliveryReportRequest": {
        "type": "object",
        "required": [
          "event"
        ],
        "additionalProperties": false,
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "rendered",
              "clicked",
              "dismissed"
            ]
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "description": "For your logs only; Tenure records its own time."
          }
        }
      },
      "DeliveryReportResponse": {
        "type": "object",
        "required": [
          "deliveryId",
          "event",
          "status",
          "changed"
        ],
        "properties": {
          "deliveryId": {
            "type": "string"
          },
          "event": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "sent",
              "delivered",
              "clicked",
              "dismissed",
              "accepted",
              "suppressed",
              "expired"
            ]
          },
          "changed": {
            "type": "boolean",
            "description": "false when the event was already recorded or the delivery has moved past it."
          }
        }
      },
      "EnableRequest": {
        "type": "object",
        "required": [
          "sessionId"
        ],
        "properties": {
          "sessionId": {
            "type": "string"
          },
          "action": {
            "type": "string",
            "enum": [
              "accept",
              "decline",
              "cancel",
              "abandon"
            ],
            "default": "accept",
            "description": "accept = execute the offer. cancel/decline = let the cancel proceed. abandon = closed without deciding."
          },
          "offerId": {
            "type": "string",
            "description": "Optional: the offer id Tenure returned; accepting checks it is the one presented."
          },
          "pauseDays": {
            "type": "integer",
            "description": "For a pause offer with several lengths (its `effect.options`)."
          }
        },
        "additionalProperties": false
      },
      "EnableResponse": {
        "type": "object",
        "required": [
          "sessionId",
          "status",
          "executionStatus",
          "outcome",
          "receipt"
        ],
        "properties": {
          "sessionId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "OPEN",
              "PASSED",
              "ACCEPTED",
              "DECLINED",
              "CANCELLED",
              "ABANDONED",
              "EXPIRED",
              "RESOLVING",
              "FULFILLING",
              "ESCALATED"
            ]
          },
          "executionStatus": {
            "type": "string",
            "enum": [
              "NONE",
              "PENDING",
              "RESERVED",
              "DONE",
              "HOST",
              "UNAPPLIED",
              "FAILED"
            ]
          },
          "outcome": {
            "type": "string",
            "enum": [
              "saved",
              "cancelled",
              "failed",
              "pending",
              "escalated",
              "already_resolved"
            ],
            "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
          },
          "receipt": {
            "type": "object",
            "properties": {
              "lines": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "What changes, in customer-facing words. Read them back."
              }
            }
          },
          "savedMrrCents": {
            "type": "integer",
            "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
          },
          "isTest": {
            "type": "boolean"
          },
          "executionLog": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "EscalateRequest": {
        "type": "object",
        "required": [
          "sessionId"
        ],
        "properties": {
          "sessionId": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "maxLength": 2000
          },
          "summary": {
            "type": "string",
            "maxLength": 4000
          },
          "platform": {
            "type": "string"
          },
          "conversationId": {
            "type": "string"
          }
        }
      },
      "EscalateResponse": {
        "type": "object",
        "properties": {
          "sessionId": {
            "type": "string"
          },
          "escalated": {
            "type": "boolean",
            "const": true
          },
          "status": {
            "type": "string"
          },
          "executionStatus": {
            "type": "string"
          },
          "handoffNote": {
            "type": "string",
            "description": "Paste into the ticket for the human."
          },
          "dashboardUrl": {
            "type": "string"
          },
          "offer": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          }
        }
      },
      "Ping": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "org": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "keyName": {
            "type": "string"
          },
          "keyPrefix": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "read",
                "decide",
                "draft_write"
              ]
            }
          },
          "isTest": {
            "type": "boolean"
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "serverTime": {
            "type": "string",
            "format": "date-time"
          },
          "docs": {
            "type": "object",
            "description": "Where to read the documentation: the index, llms.txt (one line per page), llms-full.txt (every page in one file) and this OpenAPI document.",
            "properties": {
              "index": {
                "type": "string",
                "format": "uri"
              },
              "llms": {
                "type": "string",
                "format": "uri"
              },
              "llmsFull": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "Figure": {
        "type": "object",
        "required": [
          "label",
          "kind",
          "unit",
          "value",
          "n",
          "of",
          "maturity",
          "source"
        ],
        "description": "One reported number with what it is and what it rests on. `value` is the count, the rate (0–1; null when withheld below the minimum denominator of 20, so only `numerator` and `n` are reported) or the amount in minor units (null when withheld). `n` is what the figure rests on and `of` what n counts (null for a count, which is its own n).",
        "properties": {
          "label": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "observed",
              "attributed",
              "estimated",
              "modeled"
            ],
            "description": "observed = counted from recorded decisions and billing; attributed = linked by timing only."
          },
          "unit": {
            "type": "string",
            "enum": [
              "count",
              "rate",
              "money"
            ]
          },
          "value": {
            "type": [
              "number",
              "null"
            ]
          },
          "n": {
            "type": "integer"
          },
          "of": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "eligible_moments",
              "cancel_clicks",
              "accepted",
              "executed",
              "subscribers",
              "mature_accepted",
              "arm_moments",
              "model_calls",
              "source_transactions",
              "cancellations",
              "subscriptions",
              "renewals",
              "shown",
              null
            ]
          },
          "numerator": {
            "type": "integer"
          },
          "interval": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "lower": {
                "type": "number"
              },
              "upper": {
                "type": "number"
              }
            }
          },
          "currency": {
            "type": "string"
          },
          "sourceTransactions": {
            "type": "integer"
          },
          "parts": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "withheld": {
            "type": "object",
            "additionalProperties": true
          },
          "maturity": {
            "type": "object",
            "additionalProperties": true
          },
          "horizon": {
            "type": "object",
            "additionalProperties": true
          },
          "source": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "ChainSession": {
        "type": "object",
        "description": "The compact session block every chain endpoint returns.",
        "required": [
          "sessionId",
          "status",
          "outcome"
        ],
        "properties": {
          "sessionId": {
            "type": "string",
            "description": "Tenure's session id."
          },
          "externalSessionId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The X-Session-Id currently pointing at this session."
          },
          "customerId": {
            "type": "string"
          },
          "subscriptionId": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "executionStatus": {
            "type": "string"
          },
          "outcome": {
            "type": "string",
            "enum": [
              "open",
              "pending",
              "retained",
              "churned",
              "abandoned",
              "no_intent",
              "superseded",
              "failed"
            ]
          },
          "isTest": {
            "type": "boolean"
          },
          "noIntent": {
            "type": "boolean",
            "description": "true when the conversation was never a cancel attempt; the session is out of every count."
          },
          "recommendationId": {
            "type": "string",
            "description": "The current recommendation id (= sessionId)."
          },
          "offer": {
            "type": [
              "object",
              "null"
            ],
            "description": "The published offer this attempt presented, if any.",
            "properties": {
              "id": {
                "type": "string"
              },
              "kind": {
                "type": "string"
              },
              "headline": {
                "type": "string"
              },
              "declined": {
                "type": "boolean",
                "description": "The delivery was reported dismissed."
              }
            }
          },
          "savedMrrCents": {
            "type": "integer",
            "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "resolvedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Refund": {
        "type": "object",
        "description": "One refund Tenure carried out (lib/refunds/refund.ts). status is an execution status: DONE, FAILED, PENDING when the provider answered without confirming either way, or AWAITING_APPROVAL while an owner or admin has still to approve it (spending limits).",
        "required": [
          "id",
          "status",
          "amountCents",
          "currency"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "RESERVED",
              "DONE",
              "FAILED",
              "PENDING",
              "AWAITING_APPROVAL"
            ]
          },
          "provider": {
            "type": "string",
            "description": "stripe, chargebee, http, or none."
          },
          "isTest": {
            "type": "boolean"
          },
          "amountCents": {
            "type": "integer",
            "description": "What the provider confirmed, in minor units of `currency`; 0 unless DONE."
          },
          "requestedCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The amount asked for; null = the full refundable amount."
          },
          "currency": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "The provider's refund / transaction id."
          },
          "detail": {
            "type": [
              "string",
              "null"
            ]
          },
          "transaction": {
            "type": "object",
            "properties": {
              "invoiceId": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Mirrored invoice id (GET /subscriptions/{id}/transactions)."
              },
              "remoteInvoiceId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "chargeId": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "sessionId": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "approval": {
            "type": [
              "object",
              "null"
            ],
            "description": "Set when the refund was held to the spending limits and had to wait: waiting, approved, declined or expired.",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "waiting",
                  "approved",
                  "declined",
                  "expired"
                ]
              },
              "expiresAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "decidedAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          }
        }
      },
      "Transaction": {
        "type": "object",
        "description": "One invoice of a subscription, from the Invoice mirror or the provider.",
        "required": [
          "id",
          "provider",
          "remoteId",
          "status",
          "amountPaidCents",
          "currency"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Mirrored: Tenure's invoice id (accepted by /transactions/{id}/refund). Provider: the provider's invoice id."
          },
          "provider": {
            "type": "string"
          },
          "remoteId": {
            "type": "string",
            "description": "The provider's invoice id."
          },
          "status": {
            "type": "string",
            "description": "paid, failed, open, void, draft..."
          },
          "amountPaidCents": {
            "type": "integer"
          },
          "amountRefundedCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "null = never recorded."
          },
          "refundableCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Available balance after provider credit reservations, separately from cash refunded. null means current availability is unknown (including mirrored Chargebee invoices); refund execution rechecks billing."
          },
          "currency": {
            "type": "string"
          },
          "paidAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "createdAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "hostedInvoiceUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "mirror",
              "provider"
            ]
          },
          "subscriptionIds": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "refunds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Refund"
            },
            "description": "Refunds Tenure issued against this invoice."
          }
        }
      },
      "Subscription": {
        "type": "object",
        "description": "One subscription Tenure can tie to a subscriber.",
        "properties": {
          "id": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "record",
              "recorded",
              "observed"
            ],
            "description": "record: the billing subscription on the customer. recorded: attributes.subscriptionIds. observed: seen in a provider event."
          },
          "status": {
            "type": "string"
          },
          "plan": {
            "type": [
              "string",
              "null"
            ]
          },
          "mrrCents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "billingInterval": {
            "type": [
              "string",
              "null"
            ]
          },
          "currentPeriodEndsAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "cancellationScheduled": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "endedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "SubscriptionList": {
        "type": "object",
        "required": [
          "subscriptions"
        ],
        "properties": {
          "customerId": {
            "type": "string"
          },
          "id": {
            "type": "string",
            "description": "Tenure's customer id."
          },
          "status": {
            "type": "string"
          },
          "plan": {
            "type": "string"
          },
          "subscriptions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Subscription"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "environment_mismatch",
                  "batch_too_large",
                  "revision_conflict",
                  "invalid_api_key",
                  "key_expired",
                  "scope_denied",
                  "human_required",
                  "subscription_not_verified",
                  "validation_error",
                  "bad_json",
                  "payload_too_large",
                  "customer_not_found",
                  "session_not_found",
                  "not_found",
                  "session_closed",
                  "offer_ineligible",
                  "idempotency_conflict",
                  "rate_limited",
                  "over_spending_limit",
                  "billing_failed",
                  "internal_error"
                ]
              },
              "message": {
                "type": "string"
              },
              "ref": {
                "type": "string",
                "description": "Server log reference (5xx only)."
              },
              "retryAfter": {
                "type": "integer"
              },
              "sessionId": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            },
            "additionalProperties": true
          }
        }
      }
    },
    "x-error-codes": {
      "environment_mismatch": {
        "status": 403,
        "description": "The key or subscriber cannot write to the requested environment."
      },
      "batch_too_large": {
        "status": 413,
        "description": "Send at most 100 lifecycle fact events per batch."
      },
      "revision_conflict": {
        "status": 409,
        "description": "The resource changed since it was read. Reload its revision before retrying."
      },
      "invalid_api_key": {
        "status": 401,
        "description": "Missing, unknown or revoked API key."
      },
      "key_expired": {
        "status": 401,
        "description": "The API key's expiresAt is in the past."
      },
      "scope_denied": {
        "status": 403,
        "description": "The API key does not carry the scope this operation needs."
      },
      "human_required": {
        "status": 403,
        "description": "Publishing, enabling, pausing, approving and confirming need a signed-in owner or admin. Keys and agents can draft and submit for review."
      },
      "subscription_not_verified": {
        "status": 403,
        "description": "The subscriptionId can't be tied to this subscriber: it isn't on their record, recorded for them or (with signed identity) owned by their Stripe customer."
      },
      "validation_error": {
        "status": 400,
        "description": "The request body or query failed validation. message lists the fields."
      },
      "bad_json": {
        "status": 400,
        "description": "The request body is not valid JSON."
      },
      "payload_too_large": {
        "status": 413,
        "description": "The request body is larger than this endpoint accepts."
      },
      "customer_not_found": {
        "status": 404,
        "description": "No customer matches the given externalId/email."
      },
      "session_not_found": {
        "status": 404,
        "description": "No cancel session with that id exists in this workspace."
      },
      "not_found": {
        "status": 404,
        "description": "The resource does not exist."
      },
      "session_closed": {
        "status": 409,
        "description": "The session is already resolved (accepted/cancelled/expired) and cannot be changed."
      },
      "offer_ineligible": {
        "status": 409,
        "description": "The session carries no approved offer, or the offerId is not one that was shown."
      },
      "idempotency_conflict": {
        "status": 409,
        "description": "The same Idempotency-Key was reused with a different request body."
      },
      "rate_limited": {
        "status": 429,
        "description": "Too many requests; honour Retry-After."
      },
      "over_spending_limit": {
        "status": 422,
        "description": "A refund by API key would take this month's spending past the workspace's monthly budget (Settings › Spending and safety)."
      },
      "billing_failed": {
        "status": 502,
        "description": "The billing provider or host webhook rejected the change."
      },
      "internal_error": {
        "status": 500,
        "description": "Unexpected server error; quote `ref` when reporting it."
      }
    }
  },
  "paths": {
    "/api/v1/ping": {
      "get": {
        "operationId": "ping",
        "summary": "Connection check",
        "description": "Verifies the API key and returns the workspace, key name, scopes, test flag and server time. Call once when configuring an integration.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "org": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        }
                      }
                    },
                    "keyName": {
                      "type": "string"
                    },
                    "keyPrefix": {
                      "type": "string"
                    },
                    "scopes": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "read",
                          "decide",
                          "draft_write"
                        ]
                      }
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "expiresAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "serverTime": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "docs": {
                      "type": "object",
                      "description": "Where to read the documentation: the index, llms.txt (one line per page), llms-full.txt (every page in one file) and this OpenAPI document.",
                      "properties": {
                        "index": {
                          "type": "string",
                          "format": "uri"
                        },
                        "llms": {
                          "type": "string",
                          "format": "uri"
                        },
                        "llmsFull": {
                          "type": "string",
                          "format": "uri"
                        },
                        "openapi": {
                          "type": "string",
                          "format": "uri"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "org": {
                    "id": "org_1",
                    "name": "Acme Streaming"
                  },
                  "keyName": "Intercom Fin",
                  "keyPrefix": "ck_live_AQtLKXi",
                  "scopes": [
                    "*"
                  ],
                  "isTest": false,
                  "expiresAt": null,
                  "serverTime": "2026-09-10T10:00:00.000Z",
                  "docs": {
                    "index": "https://app.tenure.example/docs",
                    "llms": "https://app.tenure.example/llms.txt",
                    "llmsFull": "https://app.tenure.example/llms-full.txt",
                    "openapi": "https://app.tenure.example/api/openapi.json"
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/recommend": {
      "post": {
        "operationId": "recommend",
        "summary": "Decide a host-rendered cancellation",
        "description": "Call when a subscriber asks to cancel in your UI or to your agent. Runs the published Cancellations plan with the widget's gates, deadline and ledger, records the attempt and returns decision=offer with exactly one approved offer to render, or decision=nothing (fallbackReason when the decision timed out or failed; preview when the plan is Preview only). Report what the subscriber saw with POST /api/v1/deliveries/{id}/report; accept or cancel with POST /api/v1/enable. Supports `Idempotency-Key`.\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "X-Session-Id",
            "in": "header",
            "required": false,
            "description": "Your conversation id; maps to one session per workspace and is reused on repeat calls. It follows the session when a new recommendation supersedes it, so it always points at the current one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string (<=200 chars). Replays the stored response for 24h; a different body with the same key is a 409 idempotency_conflict. Replays carry `Idempotent-Replayed: true`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "customerId": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Your subscriber id. Required unless email is given (or X-Session-Id names a session)."
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "traits": {
                    "$ref": "#/components/schemas/Traits"
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "A reason id from your published Cancellations plan; an unknown id is recorded as other."
                  },
                  "conversation": {
                    "type": "string",
                    "maxLength": 4000,
                    "description": "The subscriber's own words. Read as data, never as instructions; the last 1,200 characters are sent to the decision."
                  },
                  "subscriptionId": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Which of the customer's subscriptions this is about. Must be on their record; billing changes target it."
                  },
                  "language": {
                    "type": "string",
                    "maxLength": 12,
                    "description": "Copy language (BCP-47); the publication's first language when it has no copy in this one."
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "live",
                      "test"
                    ],
                    "description": "test records a test attempt. Test API keys force this."
                  },
                  "platform": {
                    "type": "string",
                    "maxLength": 60,
                    "description": "Calling platform, e.g. intercom_fin, decagon, sierra, zendesk. Stored on the session."
                  },
                  "conversationId": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Your conversation/ticket id, for tracing."
                  },
                  "externalSessionId": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Your conversation id. Normally sent as the `X-Session-Id` header instead; the header wins."
                  }
                }
              },
              "example": {
                "customerId": "demo_1",
                "reason": "too_expensive",
                "conversation": "It's getting too expensive for what I use.",
                "platform": "intercom_fin",
                "conversationId": "conv_8213"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "decision",
                    "sessionId",
                    "deliveryId",
                    "environment",
                    "isTest",
                    "offer",
                    "compliance",
                    "nextStep"
                  ],
                  "properties": {
                    "decision": {
                      "type": "string",
                      "enum": [
                        "offer",
                        "nothing"
                      ],
                      "description": "offer: render exactly this one offer beside a way to cancel. nothing: offer nothing and let them cancel."
                    },
                    "sessionId": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Null only with fallbackReason engine_error: no attempt could be recorded."
                    },
                    "deliveryId": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Report what the subscriber saw: POST /api/v1/deliveries/{deliveryId}/report."
                    },
                    "momentId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "decisionId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "status": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "executionStatus": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "environment": {
                      "type": "string",
                      "enum": [
                        "live",
                        "test"
                      ]
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "reason": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "language": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "offer": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "One approved alternative from the published plan, in its reviewed words.",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "kind": {
                          "type": "string"
                        },
                        "headline": {
                          "type": "string"
                        },
                        "body": {
                          "type": "string"
                        },
                        "ctaLabel": {
                          "type": "string"
                        },
                        "changes": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "effect": {
                          "type": "object",
                          "additionalProperties": true
                        }
                      }
                    },
                    "fallbackReason": {
                      "type": "string",
                      "enum": [
                        "timeout",
                        "error",
                        "no_key",
                        "refused",
                        "incomplete",
                        "deadline_too_short",
                        "engine_error"
                      ],
                      "description": "The decision could not be made in time or at all; the answer is nothing."
                    },
                    "preview": {
                      "type": "boolean",
                      "const": true,
                      "description": "The plan is Preview only: the attempt was recorded with what would have been offered; nothing is shown."
                    },
                    "compliance": {
                      "type": "object",
                      "properties": {
                        "exitRequired": {
                          "type": "boolean",
                          "const": true
                        },
                        "oneOfferMax": {
                          "type": "boolean",
                          "const": true
                        },
                        "environment": {
                          "type": "string",
                          "enum": [
                            "live",
                            "test"
                          ]
                        }
                      }
                    },
                    "externalSessionId": {
                      "type": "string"
                    },
                    "nextStep": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "decision": "offer",
                  "sessionId": "cmf1abc",
                  "deliveryId": "dlv_1",
                  "momentId": "mom_1",
                  "decisionId": "dec_1",
                  "status": "OPEN",
                  "executionStatus": "NONE",
                  "environment": "live",
                  "isTest": false,
                  "reason": "too_expensive",
                  "language": "en",
                  "offer": {
                    "id": "row_pause",
                    "kind": "pause",
                    "headline": "Take a break instead",
                    "body": "Pause your plan and pick up where you left off.",
                    "ctaLabel": "Pause for 30 days",
                    "changes": [
                      "No charge for 30 days."
                    ],
                    "effect": {
                      "days": 30,
                      "options": [
                        30
                      ]
                    }
                  },
                  "compliance": {
                    "exitRequired": true,
                    "oneOfferMax": true,
                    "environment": "live"
                  },
                  "nextStep": "Show this one offer in its own words, next to a clear way to cancel."
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.; bad_json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_json",
                    "message": "The request body is not valid JSON."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.; subscription_not_verified",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "subscription_not_verified",
                    "message": "The subscriptionId can't be tied to this subscriber: it isn't on their record, recorded for them or (with signed identity) owned by their Stripe customer."
                  }
                }
              }
            }
          },
          "409": {
            "description": "session_closed: The session is already resolved (accepted/cancelled/expired) and cannot be changed.; idempotency_conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "idempotency_conflict",
                    "message": "The same Idempotency-Key was reused with a different request body."
                  }
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests; honour Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests; honour Retry-After."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/deliveries/{id}/report": {
      "post": {
        "operationId": "delivery_report",
        "summary": "Report what happened to a host-rendered offer",
        "description": "rendered once it is on screen, clicked when the subscriber opens it, dismissed when they say no. Reports only move forward and repeat safely (changed=false). A test key reaches test deliveries only. Acceptance is not a report: call POST /api/v1/enable.\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string (<=200 chars). Replays the stored response for 24h; a different body with the same key is a 409 idempotency_conflict. Replays carry `Idempotent-Replayed: true`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "event"
                ],
                "additionalProperties": false,
                "properties": {
                  "event": {
                    "type": "string",
                    "enum": [
                      "rendered",
                      "clicked",
                      "dismissed"
                    ]
                  },
                  "at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "For your logs only; Tenure records its own time."
                  }
                }
              },
              "example": {
                "event": "rendered"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deliveryId",
                    "event",
                    "status",
                    "changed"
                  ],
                  "properties": {
                    "deliveryId": {
                      "type": "string"
                    },
                    "event": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "sent",
                        "delivered",
                        "clicked",
                        "dismissed",
                        "accepted",
                        "suppressed",
                        "expired"
                      ]
                    },
                    "changed": {
                      "type": "boolean",
                      "description": "false when the event was already recorded or the delivery has moved past it."
                    }
                  }
                },
                "example": {
                  "deliveryId": "dlv_1",
                  "event": "rendered",
                  "status": "delivered",
                  "changed": true
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.; bad_json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_json",
                    "message": "The request body is not valid JSON."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "not_found: The resource does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "The resource does not exist."
                  }
                }
              }
            }
          },
          "409": {
            "description": "session_closed: The session is already resolved (accepted/cancelled/expired) and cannot be changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "session_closed",
                    "message": "The session is already resolved (accepted/cancelled/expired) and cannot be changed."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/enable": {
      "post": {
        "operationId": "enable",
        "summary": "Enable the offer (or confirm the cancel)",
        "description": "The customer said yes (action=accept) or no (action=cancel). Executes the billing change server-side with guardrails intact and returns an outcome plus receipt lines to read back. Supports `Idempotency-Key`; repeating the same action on a closed session returns outcome=already_resolved.\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "X-Session-Id",
            "in": "header",
            "required": false,
            "description": "Your conversation id; maps to one session per workspace and is reused on repeat calls. It follows the session when a new recommendation supersedes it, so it always points at the current one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string (<=200 chars). Replays the stored response for 24h; a different body with the same key is a 409 idempotency_conflict. Replays carry `Idempotent-Replayed: true`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "sessionId"
                ],
                "properties": {
                  "sessionId": {
                    "type": "string"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "accept",
                      "decline",
                      "cancel",
                      "abandon"
                    ],
                    "default": "accept",
                    "description": "accept = execute the offer. cancel/decline = let the cancel proceed. abandon = closed without deciding."
                  },
                  "offerId": {
                    "type": "string",
                    "description": "Optional: the offer id Tenure returned; accepting checks it is the one presented."
                  },
                  "pauseDays": {
                    "type": "integer",
                    "description": "For a pause offer with several lengths (its `effect.options`)."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "sessionId": "cmf1abc",
                "action": "accept"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "sessionId",
                    "status",
                    "executionStatus",
                    "outcome",
                    "receipt"
                  ],
                  "properties": {
                    "sessionId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "OPEN",
                        "PASSED",
                        "ACCEPTED",
                        "DECLINED",
                        "CANCELLED",
                        "ABANDONED",
                        "EXPIRED",
                        "RESOLVING",
                        "FULFILLING",
                        "ESCALATED"
                      ]
                    },
                    "executionStatus": {
                      "type": "string",
                      "enum": [
                        "NONE",
                        "PENDING",
                        "RESERVED",
                        "DONE",
                        "HOST",
                        "UNAPPLIED",
                        "FAILED"
                      ]
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "saved",
                        "cancelled",
                        "failed",
                        "pending",
                        "escalated",
                        "already_resolved"
                      ],
                      "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "What changes, in customer-facing words. Read them back."
                        }
                      }
                    },
                    "savedMrrCents": {
                      "type": "integer",
                      "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "executionLog": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                },
                "example": {
                  "sessionId": "cmf1abc",
                  "status": "ACCEPTED",
                  "executionStatus": "DONE",
                  "outcome": "saved",
                  "receipt": {
                    "lines": [
                      "$15/mo → $12/mo for 3 months, then $15/mo",
                      "Applied to your next invoice"
                    ]
                  },
                  "savedMrrCents": 1500,
                  "isTest": false,
                  "executionLog": [
                    {
                      "at": "2026-09-10T10:00:01.000Z",
                      "actor": "agent",
                      "step": "apply_offer",
                      "ok": true,
                      "mode": "stripe",
                      "detail": "coupon applied"
                    }
                  ]
                }
              }
            }
          },
          "202": {
            "description": "outcome=pending: awaiting billing confirmation. Poll GET /api/v1/sessions/{id}; do not promise success or send a conflicting action.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "sessionId",
                    "status",
                    "executionStatus",
                    "outcome",
                    "receipt"
                  ],
                  "properties": {
                    "sessionId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "OPEN",
                        "PASSED",
                        "ACCEPTED",
                        "DECLINED",
                        "CANCELLED",
                        "ABANDONED",
                        "EXPIRED",
                        "RESOLVING",
                        "FULFILLING",
                        "ESCALATED"
                      ]
                    },
                    "executionStatus": {
                      "type": "string",
                      "enum": [
                        "NONE",
                        "PENDING",
                        "RESERVED",
                        "DONE",
                        "HOST",
                        "UNAPPLIED",
                        "FAILED"
                      ]
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "saved",
                        "cancelled",
                        "failed",
                        "pending",
                        "escalated",
                        "already_resolved"
                      ],
                      "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "What changes, in customer-facing words. Read them back."
                        }
                      }
                    },
                    "savedMrrCents": {
                      "type": "integer",
                      "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "executionLog": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "session_not_found: No cancel session with that id exists in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "session_not_found",
                    "message": "No cancel session with that id exists in this workspace."
                  }
                }
              }
            }
          },
          "409": {
            "description": "session_closed: The session is already resolved (accepted/cancelled/expired) and cannot be changed.; offer_ineligible; idempotency_conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "idempotency_conflict",
                    "message": "The same Idempotency-Key was reused with a different request body."
                  }
                }
              }
            }
          },
          "422": {
            "description": "outcome=failed: billing failed or no executor is connected. Read executionStatus and the receipt; UNAPPLIED requires completing the action in the account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "sessionId",
                    "status",
                    "executionStatus",
                    "outcome",
                    "receipt"
                  ],
                  "properties": {
                    "sessionId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "OPEN",
                        "PASSED",
                        "ACCEPTED",
                        "DECLINED",
                        "CANCELLED",
                        "ABANDONED",
                        "EXPIRED",
                        "RESOLVING",
                        "FULFILLING",
                        "ESCALATED"
                      ]
                    },
                    "executionStatus": {
                      "type": "string",
                      "enum": [
                        "NONE",
                        "PENDING",
                        "RESERVED",
                        "DONE",
                        "HOST",
                        "UNAPPLIED",
                        "FAILED"
                      ]
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "saved",
                        "cancelled",
                        "failed",
                        "pending",
                        "escalated",
                        "already_resolved"
                      ],
                      "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "What changes, in customer-facing words. Read them back."
                        }
                      }
                    },
                    "savedMrrCents": {
                      "type": "integer",
                      "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "executionLog": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "billing_failed: The billing provider or host webhook rejected the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "billing_failed",
                    "message": "The billing provider or host webhook rejected the change."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/escalate": {
      "post": {
        "operationId": "escalate",
        "summary": "Escalate to a human",
        "description": "Marks the session for a person (EventLog `session.escalated`, host webhook `session.escalated`). The session stays open so the human can still enable or cancel. Returns a hand-off note.\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "sessionId"
                ],
                "properties": {
                  "sessionId": {
                    "type": "string"
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "summary": {
                    "type": "string",
                    "maxLength": 4000
                  },
                  "platform": {
                    "type": "string"
                  },
                  "conversationId": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "sessionId": "cmf1abc",
                "reason": "customer asked for a refund we cannot promise",
                "summary": "Ana wants a refund for last month and will cancel otherwise."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sessionId": {
                      "type": "string"
                    },
                    "escalated": {
                      "type": "boolean",
                      "const": true
                    },
                    "status": {
                      "type": "string"
                    },
                    "executionStatus": {
                      "type": "string"
                    },
                    "handoffNote": {
                      "type": "string",
                      "description": "Paste into the ticket for the human."
                    },
                    "dashboardUrl": {
                      "type": "string"
                    },
                    "offer": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "sessionId": "cmf1abc",
                  "escalated": true,
                  "status": "OPEN",
                  "executionStatus": "NONE",
                  "handoffNote": "Hand-off from AI agent for Ana Ruiz ...",
                  "dashboardUrl": "https://app.example.com/sessions/cmf1abc",
                  "offer": {
                    "id": "off_disc20",
                    "name": "20% off 3 months",
                    "type": "DISCOUNT"
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "session_not_found: No cancel session with that id exists in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "session_not_found",
                    "message": "No cancel session with that id exists in this workspace."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/subscriptions/{id}/recommended-offer": {
      "post": {
        "operationId": "recommended_offer",
        "summary": "Decide a host-rendered cancellation for one subscription",
        "description": "POST /api/v1/recommend addressed to a subscription: the same published decision, plus `recommendationId` (= sessionId) to pass to apply. `{id}` must be a subscription on a customer's record (or send customerId/email with it).\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Session-Id",
            "in": "header",
            "required": false,
            "description": "Your conversation id; maps to one session per workspace and is reused on repeat calls. It follows the session when a new recommendation supersedes it, so it always points at the current one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string (<=200 chars). Replays the stored response for 24h; a different body with the same key is a 409 idempotency_conflict. Replays carry `Idempotent-Replayed: true`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "description": "The recommend body in the chain's words. `reason` is the customer's own text; `category` is a Tenure reason id or a loose label (pricing, usage...) mapped to one.",
                "properties": {
                  "reason": {
                    "type": "string",
                    "maxLength": 4000
                  },
                  "category": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "conversation": {
                    "type": "string",
                    "maxLength": 4000
                  },
                  "customerId": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "platform": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "conversationId": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "language": {
                    "type": "string",
                    "maxLength": 12
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "live",
                      "test"
                    ]
                  }
                }
              },
              "example": {
                "reason": "I only need the basic features now",
                "category": "pricing"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "type": "object",
                      "required": [
                        "decision",
                        "sessionId",
                        "deliveryId",
                        "environment",
                        "isTest",
                        "offer",
                        "compliance",
                        "nextStep"
                      ],
                      "properties": {
                        "decision": {
                          "type": "string",
                          "enum": [
                            "offer",
                            "nothing"
                          ],
                          "description": "offer: render exactly this one offer beside a way to cancel. nothing: offer nothing and let them cancel."
                        },
                        "sessionId": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Null only with fallbackReason engine_error: no attempt could be recorded."
                        },
                        "deliveryId": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Report what the subscriber saw: POST /api/v1/deliveries/{deliveryId}/report."
                        },
                        "momentId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "decisionId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "status": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "executionStatus": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "environment": {
                          "type": "string",
                          "enum": [
                            "live",
                            "test"
                          ]
                        },
                        "isTest": {
                          "type": "boolean"
                        },
                        "reason": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "language": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "offer": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "description": "One approved alternative from the published plan, in its reviewed words.",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "kind": {
                              "type": "string"
                            },
                            "headline": {
                              "type": "string"
                            },
                            "body": {
                              "type": "string"
                            },
                            "ctaLabel": {
                              "type": "string"
                            },
                            "changes": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            },
                            "effect": {
                              "type": "object",
                              "additionalProperties": true
                            }
                          }
                        },
                        "fallbackReason": {
                          "type": "string",
                          "enum": [
                            "timeout",
                            "error",
                            "no_key",
                            "refused",
                            "incomplete",
                            "deadline_too_short",
                            "engine_error"
                          ],
                          "description": "The decision could not be made in time or at all; the answer is nothing."
                        },
                        "preview": {
                          "type": "boolean",
                          "const": true,
                          "description": "The plan is Preview only: the attempt was recorded with what would have been offered; nothing is shown."
                        },
                        "compliance": {
                          "type": "object",
                          "properties": {
                            "exitRequired": {
                              "type": "boolean",
                              "const": true
                            },
                            "oneOfferMax": {
                              "type": "boolean",
                              "const": true
                            },
                            "environment": {
                              "type": "string",
                              "enum": [
                                "live",
                                "test"
                              ]
                            }
                          }
                        },
                        "externalSessionId": {
                          "type": "string"
                        },
                        "nextStep": {
                          "type": "string"
                        }
                      }
                    }
                  ],
                  "properties": {
                    "recommendationId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "subscriptionId": {
                      "type": "string"
                    },
                    "category": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "reasonId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                },
                "example": {
                  "decision": "offer",
                  "sessionId": "cmf1def",
                  "recommendationId": "cmf1def",
                  "deliveryId": "dlv_1",
                  "subscriptionId": "sub_123",
                  "offer": {
                    "id": "row_basic",
                    "kind": "downgrade",
                    "headline": "Move to Basic for $8/mo",
                    "body": "Keep your reports on the Basic plan.",
                    "ctaLabel": "Switch to Basic",
                    "changes": [
                      "Pro $15/mo → Basic $8/mo from the next invoice."
                    ],
                    "effect": {
                      "newPriceCents": 800,
                      "currency": "usd",
                      "loses": []
                    }
                  },
                  "externalSessionId": "conv_8213"
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.; bad_json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_json",
                    "message": "The request body is not valid JSON."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "customer_not_found: No customer matches the given externalId/email.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "customer_not_found",
                    "message": "No customer matches the given externalId/email."
                  }
                }
              }
            }
          },
          "409": {
            "description": "session_closed: The session is already resolved (accepted/cancelled/expired) and cannot be changed.; idempotency_conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "idempotency_conflict",
                    "message": "The same Idempotency-Key was reused with a different request body."
                  }
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests; honour Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests; honour Retry-After."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/offers/{id}/apply": {
      "post": {
        "operationId": "offer_apply",
        "summary": "The customer accepted this offer",
        "description": "Alias of POST /api/v1/enable {action: accept, offerId}: the same execution path, receipt and status codes (202 pending, 422 failed). `{id}` is the offer id you were given; send `recommendationId` so a stale recommendation is caught (409 offer_ineligible).\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Session-Id",
            "in": "header",
            "required": false,
            "description": "Your conversation id; maps to one session per workspace and is reused on repeat calls. It follows the session when a new recommendation supersedes it, so it always points at the current one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string (<=200 chars). Replays the stored response for 24h; a different body with the same key is a 409 idempotency_conflict. Replays carry `Idempotent-Replayed: true`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "subscriptionId": {
                    "type": "string"
                  },
                  "recommendationId": {
                    "type": "string",
                    "description": "The `recommendationId` you were given. A stale one is 409 offer_ineligible."
                  },
                  "sessionId": {
                    "type": "string",
                    "description": "Only when you cannot send `X-Session-Id`."
                  },
                  "pauseDays": {
                    "type": "integer",
                    "description": "For PAUSE offers with several lengths."
                  }
                }
              },
              "example": {
                "subscriptionId": "sub_123",
                "recommendationId": "cmf1def"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "type": "object",
                      "required": [
                        "sessionId",
                        "status",
                        "executionStatus",
                        "outcome",
                        "receipt"
                      ],
                      "properties": {
                        "sessionId": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "OPEN",
                            "PASSED",
                            "ACCEPTED",
                            "DECLINED",
                            "CANCELLED",
                            "ABANDONED",
                            "EXPIRED",
                            "RESOLVING",
                            "FULFILLING",
                            "ESCALATED"
                          ]
                        },
                        "executionStatus": {
                          "type": "string",
                          "enum": [
                            "NONE",
                            "PENDING",
                            "RESERVED",
                            "DONE",
                            "HOST",
                            "UNAPPLIED",
                            "FAILED"
                          ]
                        },
                        "outcome": {
                          "type": "string",
                          "enum": [
                            "saved",
                            "cancelled",
                            "failed",
                            "pending",
                            "escalated",
                            "already_resolved"
                          ],
                          "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
                        },
                        "receipt": {
                          "type": "object",
                          "properties": {
                            "lines": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              },
                              "description": "What changes, in customer-facing words. Read them back."
                            }
                          }
                        },
                        "savedMrrCents": {
                          "type": "integer",
                          "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                        },
                        "isTest": {
                          "type": "boolean"
                        },
                        "executionLog": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": true
                          }
                        }
                      }
                    }
                  ],
                  "properties": {
                    "offerId": {
                      "type": "string"
                    },
                    "recommendationId": {
                      "type": "string"
                    },
                    "externalSessionId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                },
                "example": {
                  "sessionId": "cmf1def",
                  "offerId": "off_basic",
                  "recommendationId": "cmf1def",
                  "externalSessionId": "conv_8213",
                  "status": "ACCEPTED",
                  "executionStatus": "DONE",
                  "outcome": "saved",
                  "receipt": {
                    "lines": [
                      "Pro $15/mo → Basic $8/mo from the next invoice"
                    ]
                  },
                  "savedMrrCents": 800,
                  "isTest": false
                }
              }
            }
          },
          "202": {
            "description": "outcome=pending: awaiting billing confirmation. Poll GET /api/v1/sessions/{id}; do not promise success or send a conflicting action.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "sessionId",
                    "status",
                    "executionStatus",
                    "outcome",
                    "receipt"
                  ],
                  "properties": {
                    "sessionId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "OPEN",
                        "PASSED",
                        "ACCEPTED",
                        "DECLINED",
                        "CANCELLED",
                        "ABANDONED",
                        "EXPIRED",
                        "RESOLVING",
                        "FULFILLING",
                        "ESCALATED"
                      ]
                    },
                    "executionStatus": {
                      "type": "string",
                      "enum": [
                        "NONE",
                        "PENDING",
                        "RESERVED",
                        "DONE",
                        "HOST",
                        "UNAPPLIED",
                        "FAILED"
                      ]
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "saved",
                        "cancelled",
                        "failed",
                        "pending",
                        "escalated",
                        "already_resolved"
                      ],
                      "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "What changes, in customer-facing words. Read them back."
                        }
                      }
                    },
                    "savedMrrCents": {
                      "type": "integer",
                      "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "executionLog": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "session_not_found: No cancel session with that id exists in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "session_not_found",
                    "message": "No cancel session with that id exists in this workspace."
                  }
                }
              }
            }
          },
          "409": {
            "description": "session_closed: The session is already resolved (accepted/cancelled/expired) and cannot be changed.; offer_ineligible; idempotency_conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "idempotency_conflict",
                    "message": "The same Idempotency-Key was reused with a different request body."
                  }
                }
              }
            }
          },
          "422": {
            "description": "outcome=failed: billing failed or no executor is connected. Read executionStatus and the receipt; UNAPPLIED requires completing the action in the account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "sessionId",
                    "status",
                    "executionStatus",
                    "outcome",
                    "receipt"
                  ],
                  "properties": {
                    "sessionId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "OPEN",
                        "PASSED",
                        "ACCEPTED",
                        "DECLINED",
                        "CANCELLED",
                        "ABANDONED",
                        "EXPIRED",
                        "RESOLVING",
                        "FULFILLING",
                        "ESCALATED"
                      ]
                    },
                    "executionStatus": {
                      "type": "string",
                      "enum": [
                        "NONE",
                        "PENDING",
                        "RESERVED",
                        "DONE",
                        "HOST",
                        "UNAPPLIED",
                        "FAILED"
                      ]
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "saved",
                        "cancelled",
                        "failed",
                        "pending",
                        "escalated",
                        "already_resolved"
                      ],
                      "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "What changes, in customer-facing words. Read them back."
                        }
                      }
                    },
                    "savedMrrCents": {
                      "type": "integer",
                      "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "executionLog": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/offers/{id}/decline": {
      "post": {
        "operationId": "offer_decline",
        "summary": "The customer refused this offer",
        "description": "Reports the offer dismissed (as POST /api/v1/deliveries/{id}/report with event=dismissed). Nothing in billing changes and the session stays open: cancel the subscription, or end the session.\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Session-Id",
            "in": "header",
            "required": false,
            "description": "Your conversation id; maps to one session per workspace and is reused on repeat calls. It follows the session when a new recommendation supersedes it, so it always points at the current one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "subscriptionId": {
                    "type": "string"
                  },
                  "recommendationId": {
                    "type": "string"
                  },
                  "sessionId": {
                    "type": "string"
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Why they said no, for reporting."
                  }
                }
              },
              "example": {
                "recommendationId": "cmf1def"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ChainSession"
                    }
                  ],
                  "properties": {
                    "declined": {
                      "type": "boolean"
                    },
                    "offerId": {
                      "type": "string"
                    },
                    "nextStep": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "sessionId": "cmf1def",
                  "externalSessionId": "conv_8213",
                  "customerId": "demo_1",
                  "status": "OPEN",
                  "outcome": "open",
                  "declined": true,
                  "offerId": "off_basic",
                  "nextStep": "No other offer is on this session."
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "session_not_found: No cancel session with that id exists in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "session_not_found",
                    "message": "No cancel session with that id exists in this workspace."
                  }
                }
              }
            }
          },
          "409": {
            "description": "session_closed: The session is already resolved (accepted/cancelled/expired) and cannot be changed.; offer_ineligible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "offer_ineligible",
                    "message": "The session carries no approved offer, or the offerId is not one that was shown."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/subscriptions/{id}/cancel": {
      "post": {
        "operationId": "subscription_cancel",
        "summary": "Cancel the subscription",
        "description": "Alias of POST /api/v1/enable {action: cancel} for one subscription: Tenure runs the cancellation through the connected billing provider (or your fulfilment webhook) with the same receipt and status codes. `reason` and `category` are stored on the session. Without `X-Session-Id`, send `customer_id` or `email`: the subscriber's open attempt carries the cancellation. With none open, the customer is leaving through your own path: Tenure records a published attempt with nothing offered and cancels it in the same call. Returns 202 (pending) and 422 (failed) like /enable.\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Session-Id",
            "in": "header",
            "required": false,
            "description": "Your conversation id; maps to one session per workspace and is reused on repeat calls. It follows the session when a new recommendation supersedes it, so it always points at the current one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "maxLength": 10000,
                    "description": "The customer's own words; stored minimised as the session's reasonText (emails, links, phone numbers, long numbers and names replaced), never as sent."
                  },
                  "category": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "sessionId": {
                    "type": "string"
                  },
                  "customerId": {
                    "type": "string",
                    "description": "Only when cancelling without a prior session."
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              },
              "example": {
                "reason": "Switching to a competitor",
                "category": "found_alternative"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "type": "object",
                      "required": [
                        "sessionId",
                        "status",
                        "executionStatus",
                        "outcome",
                        "receipt"
                      ],
                      "properties": {
                        "sessionId": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "OPEN",
                            "PASSED",
                            "ACCEPTED",
                            "DECLINED",
                            "CANCELLED",
                            "ABANDONED",
                            "EXPIRED",
                            "RESOLVING",
                            "FULFILLING",
                            "ESCALATED"
                          ]
                        },
                        "executionStatus": {
                          "type": "string",
                          "enum": [
                            "NONE",
                            "PENDING",
                            "RESERVED",
                            "DONE",
                            "HOST",
                            "UNAPPLIED",
                            "FAILED"
                          ]
                        },
                        "outcome": {
                          "type": "string",
                          "enum": [
                            "saved",
                            "cancelled",
                            "failed",
                            "pending",
                            "escalated",
                            "already_resolved"
                          ],
                          "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
                        },
                        "receipt": {
                          "type": "object",
                          "properties": {
                            "lines": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              },
                              "description": "What changes, in customer-facing words. Read them back."
                            }
                          }
                        },
                        "savedMrrCents": {
                          "type": "integer",
                          "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                        },
                        "isTest": {
                          "type": "boolean"
                        },
                        "executionLog": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": true
                          }
                        }
                      }
                    }
                  ],
                  "properties": {
                    "subscriptionId": {
                      "type": "string"
                    },
                    "externalSessionId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "reasonId": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "enum": [
                        "too_expensive",
                        "not_using",
                        "missing_features",
                        "found_alternative",
                        "technical_issues",
                        "temporary",
                        "completed",
                        "other",
                        null
                      ]
                    }
                  }
                },
                "example": {
                  "sessionId": "cmf1def",
                  "subscriptionId": "sub_123",
                  "externalSessionId": "conv_8213",
                  "reasonId": "found_alternative",
                  "status": "CANCELLED",
                  "executionStatus": "DONE",
                  "outcome": "cancelled",
                  "receipt": {
                    "lines": [
                      "Cancels at the end of the current period"
                    ]
                  },
                  "savedMrrCents": 0,
                  "isTest": false
                }
              }
            }
          },
          "202": {
            "description": "outcome=pending: awaiting billing confirmation. Poll GET /api/v1/sessions/{id}; do not promise success or send a conflicting action.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "sessionId",
                    "status",
                    "executionStatus",
                    "outcome",
                    "receipt"
                  ],
                  "properties": {
                    "sessionId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "OPEN",
                        "PASSED",
                        "ACCEPTED",
                        "DECLINED",
                        "CANCELLED",
                        "ABANDONED",
                        "EXPIRED",
                        "RESOLVING",
                        "FULFILLING",
                        "ESCALATED"
                      ]
                    },
                    "executionStatus": {
                      "type": "string",
                      "enum": [
                        "NONE",
                        "PENDING",
                        "RESERVED",
                        "DONE",
                        "HOST",
                        "UNAPPLIED",
                        "FAILED"
                      ]
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "saved",
                        "cancelled",
                        "failed",
                        "pending",
                        "escalated",
                        "already_resolved"
                      ],
                      "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "What changes, in customer-facing words. Read them back."
                        }
                      }
                    },
                    "savedMrrCents": {
                      "type": "integer",
                      "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "executionLog": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "session_not_found: No cancel session with that id exists in this workspace.; customer_not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "customer_not_found",
                    "message": "No customer matches the given externalId/email."
                  }
                }
              }
            }
          },
          "409": {
            "description": "session_closed: The session is already resolved (accepted/cancelled/expired) and cannot be changed.; offer_ineligible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "offer_ineligible",
                    "message": "The session carries no approved offer, or the offerId is not one that was shown."
                  }
                }
              }
            }
          },
          "422": {
            "description": "outcome=failed: billing failed or no executor is connected. Read executionStatus and the receipt; UNAPPLIED requires completing the action in the account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "sessionId",
                    "status",
                    "executionStatus",
                    "outcome",
                    "receipt"
                  ],
                  "properties": {
                    "sessionId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "OPEN",
                        "PASSED",
                        "ACCEPTED",
                        "DECLINED",
                        "CANCELLED",
                        "ABANDONED",
                        "EXPIRED",
                        "RESOLVING",
                        "FULFILLING",
                        "ESCALATED"
                      ]
                    },
                    "executionStatus": {
                      "type": "string",
                      "enum": [
                        "NONE",
                        "PENDING",
                        "RESERVED",
                        "DONE",
                        "HOST",
                        "UNAPPLIED",
                        "FAILED"
                      ]
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "saved",
                        "cancelled",
                        "failed",
                        "pending",
                        "escalated",
                        "already_resolved"
                      ],
                      "description": "saved: offer applied. cancelled: cancellation confirmed (or declined/abandoned). escalated: the attempt was handed to a person and closed that way; nothing changed on the account and it can still be accepted or cancelled. pending: billing request awaiting confirmation (HTTP 202); poll the session before changing action. failed: billing/webhook error or no connected executor (HTTP 422); inspect executionStatus and receipt before retrying. already_resolved: same action repeated on a closed session (idempotent)."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "What changes, in customer-facing words. Read them back."
                        }
                      }
                    },
                    "savedMrrCents": {
                      "type": "integer",
                      "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "executionLog": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/sessions/{id}/end": {
      "post": {
        "operationId": "session_end",
        "summary": "End the conversation",
        "description": "Close the session with what actually happened. `{id}` is the Tenure session id or your own `X-Session-Id`. Tenure applies offers and cancellations itself, so a live attempt cannot end retained or churned (409 session_closed: use /offers/{id}/apply or /subscriptions/{id}/cancel). abandoned or no_intent: they left without deciding. On an attempt that already ended, a matching outcome (retained after an accepted offer, churned after a cancellation) is an idempotent no-op. Repeating the same outcome is idempotent; a contradicting one is 409 session_closed.\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Session-Id",
            "in": "header",
            "required": false,
            "description": "Your conversation id; maps to one session per workspace and is reused on repeat calls. It follows the session when a new recommendation supersedes it, so it always points at the current one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "outcome"
                ],
                "properties": {
                  "outcome": {
                    "type": "string",
                    "enum": [
                      "retained",
                      "churned",
                      "abandoned",
                      "no_intent"
                    ],
                    "description": "abandoned: they left without deciding. no_intent: never a cancel attempt. retained / churned only confirm an attempt Tenure already closed that way (a live one is 409: apply or cancel it instead)."
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 2000
                  }
                }
              },
              "example": {
                "outcome": "abandoned"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ChainSession"
                    }
                  ],
                  "properties": {
                    "ended": {
                      "type": "boolean"
                    },
                    "changed": {
                      "type": "boolean",
                      "description": "false when the session already ended that way."
                    },
                    "requestedOutcome": {
                      "type": "string",
                      "enum": [
                        "retained",
                        "churned",
                        "abandoned",
                        "no_intent"
                      ]
                    }
                  }
                },
                "example": {
                  "sessionId": "cmf1def",
                  "externalSessionId": "conv_8213",
                  "customerId": "demo_1",
                  "status": "ABANDONED",
                  "executionStatus": "NONE",
                  "outcome": "abandoned",
                  "savedMrrCents": 0,
                  "ended": true,
                  "changed": true,
                  "requestedOutcome": "abandoned"
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "session_not_found: No cancel session with that id exists in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "session_not_found",
                    "message": "No cancel session with that id exists in this workspace."
                  }
                }
              }
            }
          },
          "409": {
            "description": "session_closed: The session is already resolved (accepted/cancelled/expired) and cannot be changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "session_closed",
                    "message": "The session is already resolved (accepted/cancelled/expired) and cannot be changed."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/sessions/{id}/refund": {
      "post": {
        "operationId": "session_refund",
        "summary": "Refund the subscriber on this session",
        "description": "Refund as a first-class action on the conversation's session (`{id}` is the Tenure session id or your `X-Session-Id`). Without `transaction_id` the latest paid invoice of the session's subscription is refunded; without an amount, everything still refundable. `cancel: true` also cancels the subscription and the session ends CANCELLED with the refund on its log. On a live session that carries a REBATE offer the refund is that offer's execution and the session ends ACCEPTED (saved). Otherwise the refund is recorded on the session, which stays open: end it with /sessions/{id}/end when the conversation is over. Every refund is a RefundExecution row, audited, mirrored onto the invoice, sent as the `refund.completed` webhook and receipted to the subscriber by email. Supports `Idempotency-Key`. 200 refunded, 202 unconfirmed (do not repeat; check the provider) or waiting for approval, 422 not issued. Held to the workspace's spending limits (Settings › Spending and safety), as offers are: a refund that would take this month's spending past the monthly budget is refused (422 `over_spending_limit`); one at or above the approval threshold, or whose amount only the billing provider knows (a full or percent refund of a transaction Tenure hasn't mirrored), answers 202 with outcome `approval_required` and is carried out when an owner or admin approves it in Overview (`refund.completed` follows); declined or unanswered, it is not issued. Without approved limits every refund waits. A refund that waits never cancels: `cancel: true` cancels only once the refund is done in this call.\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Session-Id",
            "in": "header",
            "required": false,
            "description": "Your conversation id; maps to one session per workspace and is reused on repeat calls. It follows the session when a new recommendation supersedes it, so it always points at the current one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string (<=200 chars). Replays the stored response for 24h; a different body with the same key is a 409 idempotency_conflict. Replays carry `Idempotent-Replayed: true`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amountCents": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "amount": {
                    "oneOf": [
                      {
                        "type": "string",
                        "const": "full"
                      },
                      {
                        "type": "integer",
                        "minimum": 1
                      }
                    ]
                  },
                  "percent": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 100
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "cancel": {
                    "type": "boolean",
                    "default": false,
                    "description": "true: after the refund, cancel the subscription through the same path /subscriptions/{id}/cancel takes; the session ends CANCELLED."
                  },
                  "transactionId": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "The transaction to refund (a mirrored invoice id, provider invoice id or charge id). Default: the latest paid invoice of the session's subscription."
                  }
                }
              },
              "example": {
                "amount": "full",
                "reason": "Charged after cancelling",
                "cancel": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ChainSession"
                    }
                  ],
                  "properties": {
                    "refund": {
                      "$ref": "#/components/schemas/Refund"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "refunded",
                        "pending",
                        "approval_required",
                        "declined",
                        "expired",
                        "failed"
                      ]
                    },
                    "refundedThrough": {
                      "type": "string",
                      "enum": [
                        "offer",
                        "cancel",
                        "refund"
                      ],
                      "description": "offer: the session's REBATE offer was applied as this refund. cancel: refunded, then cancelled. refund: refunded, session left as it was."
                    },
                    "cancelled": {
                      "type": "boolean"
                    },
                    "replayed": {
                      "type": "boolean",
                      "description": "true when the same refund had already been carried out and its outcome was returned again."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "sessionId": "cmf1def",
                  "externalSessionId": "conv_8213",
                  "customerId": "demo_1",
                  "status": "CANCELLED",
                  "executionStatus": "DONE",
                  "outcome": "refunded",
                  "refundedThrough": "cancel",
                  "cancelled": true,
                  "replayed": false,
                  "refund": {
                    "id": "rf_1",
                    "status": "DONE",
                    "provider": "stripe",
                    "amountCents": 1500,
                    "requestedCents": null,
                    "currency": "USD",
                    "reason": "Charged after cancelling",
                    "reference": "re_1abc",
                    "transaction": {
                      "invoiceId": "inv_local",
                      "remoteInvoiceId": "in_1abc",
                      "chargeId": "ch_1abc"
                    }
                  },
                  "receipt": {
                    "lines": [
                      "Refunded 15.00 USD to the original payment method (reference re_1abc). Refunds usually appear within 5 to 10 business days.",
                      "The subscription has been cancelled."
                    ]
                  }
                }
              }
            }
          },
          "202": {
            "description": "outcome=pending: the refund request was sent but its outcome is unconfirmed. Do not repeat it; check the billing provider, then read the refund back.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ChainSession"
                    }
                  ],
                  "properties": {
                    "refund": {
                      "$ref": "#/components/schemas/Refund"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "refunded",
                        "pending",
                        "approval_required",
                        "declined",
                        "expired",
                        "failed"
                      ]
                    },
                    "refundedThrough": {
                      "type": "string",
                      "enum": [
                        "offer",
                        "cancel",
                        "refund"
                      ],
                      "description": "offer: the session's REBATE offer was applied as this refund. cancel: refunded, then cancelled. refund: refunded, session left as it was."
                    },
                    "cancelled": {
                      "type": "boolean"
                    },
                    "replayed": {
                      "type": "boolean",
                      "description": "true when the same refund had already been carried out and its outcome was returned again."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.; bad_json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_json",
                    "message": "The request body is not valid JSON."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "session_not_found: No cancel session with that id exists in this workspace.; customer_not_found; not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "The resource does not exist."
                  }
                }
              }
            }
          },
          "409": {
            "description": "session_closed: The session is already resolved (accepted/cancelled/expired) and cannot be changed.; idempotency_conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "idempotency_conflict",
                    "message": "The same Idempotency-Key was reused with a different request body."
                  }
                }
              }
            }
          },
          "422": {
            "description": "outcome=failed: the refund was not issued (nothing to refund, already refunded in full, provider rejected it, or no billing provider is connected). refund.detail says why.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ChainSession"
                    }
                  ],
                  "properties": {
                    "refund": {
                      "$ref": "#/components/schemas/Refund"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "refunded",
                        "pending",
                        "approval_required",
                        "declined",
                        "expired",
                        "failed"
                      ]
                    },
                    "refundedThrough": {
                      "type": "string",
                      "enum": [
                        "offer",
                        "cancel",
                        "refund"
                      ],
                      "description": "offer: the session's REBATE offer was applied as this refund. cancel: refunded, then cancelled. refund: refunded, session left as it was."
                    },
                    "cancelled": {
                      "type": "boolean"
                    },
                    "replayed": {
                      "type": "boolean",
                      "description": "true when the same refund had already been carried out and its outcome was returned again."
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests; honour Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests; honour Retry-After."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/transactions/{id}/refund": {
      "post": {
        "operationId": "transaction_refund",
        "summary": "Refund one transaction",
        "description": "Direct refund of one transaction (Sirius `POST /transactions/{id}/refund`). `{id}` is a mirrored invoice id from GET /subscriptions/{id}/transactions, the provider's invoice id, or a Stripe charge / payment id. The subscriber comes from the mirrored invoice, the session named by `X-Session-Id` / `session_id`, or `customer_id` / `email`. With a session the refund is logged on it but its status is left alone: use /sessions/{id}/refund for the agent flow. Same recording, webhook and receipt as /sessions/{id}/refund. Supports `Idempotency-Key`. 200 refunded, 202 unconfirmed or waiting for approval, 422 not issued. Held to the workspace's spending limits (Settings › Spending and safety), as offers are: a refund that would take this month's spending past the monthly budget is refused (422 `over_spending_limit`); one at or above the approval threshold, or whose amount only the billing provider knows (a full or percent refund of a transaction Tenure hasn't mirrored), answers 202 with outcome `approval_required` and is carried out when an owner or admin approves it in Overview (`refund.completed` follows); declined or unanswered, it is not issued. Without approved limits every refund waits.\n\nRequired scope: `decide`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Session-Id",
            "in": "header",
            "required": false,
            "description": "Your conversation id; maps to one session per workspace and is reused on repeat calls. It follows the session when a new recommendation supersedes it, so it always points at the current one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string (<=200 chars). Replays the stored response for 24h; a different body with the same key is a 409 idempotency_conflict. Replays carry `Idempotent-Replayed: true`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "type": "object",
                    "properties": {
                      "amountCents": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "Amount to refund in minor units. Omit (or send amount: \"full\") for everything still refundable."
                      },
                      "amount": {
                        "oneOf": [
                          {
                            "type": "string",
                            "const": "full"
                          },
                          {
                            "type": "integer",
                            "minimum": 1
                          }
                        ],
                        "description": "Alias: \"full\" or an amount in minor units."
                      },
                      "percent": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 100,
                        "description": "Share of the payment to refund; ignored when an amount is given."
                      },
                      "reason": {
                        "type": "string",
                        "maxLength": 500,
                        "description": "Kept on the refund, sent to the provider as a note and read back in the receipt email."
                      }
                    }
                  }
                ],
                "properties": {
                  "customerId": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "sessionId": {
                    "type": "string",
                    "maxLength": 64
                  }
                }
              },
              "example": {
                "amount_cents": 500,
                "reason": "Goodwill for the outage",
                "customer_id": "demo_1"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "transactionId",
                    "refund",
                    "outcome"
                  ],
                  "properties": {
                    "transactionId": {
                      "type": "string"
                    },
                    "refund": {
                      "$ref": "#/components/schemas/Refund"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "refunded",
                        "pending",
                        "approval_required",
                        "declined",
                        "expired",
                        "failed"
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    },
                    "mode": {
                      "type": "string",
                      "enum": [
                        "stripe",
                        "chargebee",
                        "http",
                        "webhook",
                        "simulated"
                      ]
                    },
                    "sessionId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "transactionId": "in_1abc",
                  "outcome": "refunded",
                  "replayed": false,
                  "mode": "stripe",
                  "sessionId": null,
                  "isTest": false,
                  "refund": {
                    "id": "rf_2",
                    "status": "DONE",
                    "provider": "stripe",
                    "amountCents": 500,
                    "requestedCents": 500,
                    "currency": "USD",
                    "reason": "Goodwill for the outage",
                    "reference": "re_2abc",
                    "transaction": {
                      "invoiceId": "inv_local",
                      "remoteInvoiceId": "in_1abc",
                      "chargeId": "ch_1abc"
                    }
                  },
                  "receipt": {
                    "lines": [
                      "Refunded 5.00 USD to the original payment method (reference re_2abc). Refunds usually appear within 5 to 10 business days."
                    ]
                  }
                }
              }
            }
          },
          "202": {
            "description": "outcome=pending: the refund request was sent but its outcome is unconfirmed. Do not repeat it; check the billing provider, then read the refund back.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "transactionId",
                    "refund",
                    "outcome"
                  ],
                  "properties": {
                    "transactionId": {
                      "type": "string"
                    },
                    "refund": {
                      "$ref": "#/components/schemas/Refund"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "refunded",
                        "pending",
                        "approval_required",
                        "declined",
                        "expired",
                        "failed"
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    },
                    "mode": {
                      "type": "string",
                      "enum": [
                        "stripe",
                        "chargebee",
                        "http",
                        "webhook",
                        "simulated"
                      ]
                    },
                    "sessionId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.; bad_json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_json",
                    "message": "The request body is not valid JSON."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "customer_not_found: No customer matches the given externalId/email.; not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "The resource does not exist."
                  }
                }
              }
            }
          },
          "409": {
            "description": "idempotency_conflict: The same Idempotency-Key was reused with a different request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "idempotency_conflict",
                    "message": "The same Idempotency-Key was reused with a different request body."
                  }
                }
              }
            }
          },
          "422": {
            "description": "outcome=failed: the refund was not issued (nothing to refund, already refunded in full, provider rejected it, or no billing provider is connected). refund.detail says why.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "transactionId",
                    "refund",
                    "outcome"
                  ],
                  "properties": {
                    "transactionId": {
                      "type": "string"
                    },
                    "refund": {
                      "$ref": "#/components/schemas/Refund"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "refunded",
                        "pending",
                        "approval_required",
                        "declined",
                        "expired",
                        "failed"
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    },
                    "mode": {
                      "type": "string",
                      "enum": [
                        "stripe",
                        "chargebee",
                        "http",
                        "webhook",
                        "simulated"
                      ]
                    },
                    "sessionId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "isTest": {
                      "type": "boolean"
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "lines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests; honour Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests; honour Retry-After."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/subscriptions/{id}/transactions": {
      "get": {
        "operationId": "subscription_transactions",
        "summary": "List a subscription's transactions",
        "description": "The subscription's invoices, newest first, each with the refunds Tenure issued against it (Sirius' transactions / invoices read mirrors). Read from the Invoice mirror the billing webhooks keep; when the mirror has nothing for this subscription the provider is asked directly (`source: provider`, ids are the provider's). A test key lists test-mode invoices. Pass a mirrored `id` to /transactions/{id}/refund.\n\nRequired scope: `read`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-200, default 50",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "subscriptionId",
                    "source",
                    "transactions"
                  ],
                  "properties": {
                    "subscriptionId": {
                      "type": "string"
                    },
                    "customerId": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Your subscriber id, when the subscription is on a customer's record."
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "mirror",
                        "provider",
                        "none"
                      ]
                    },
                    "count": {
                      "type": "integer"
                    },
                    "transactions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Transaction"
                      }
                    }
                  }
                },
                "example": {
                  "subscriptionId": "sub_123",
                  "customerId": "demo_1",
                  "source": "mirror",
                  "count": 1,
                  "transactions": [
                    {
                      "id": "inv_local",
                      "provider": "stripe",
                      "remoteId": "in_1abc",
                      "status": "paid",
                      "amountPaidCents": 1500,
                      "amountRefundedCents": 0,
                      "refundableCents": 1500,
                      "currency": "USD",
                      "paidAt": "2026-09-01T00:00:00.000Z",
                      "createdAt": "2026-09-01T00:00:00.000Z",
                      "hostedInvoiceUrl": null,
                      "source": "mirror",
                      "subscriptionIds": [
                        "sub_123"
                      ],
                      "refunds": []
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests; honour Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests; honour Retry-After."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/customers/lookup": {
      "get": {
        "operationId": "customers_lookup",
        "summary": "Find the subscriber a conversation is about",
        "description": "Look a customer up by email, your subscriber id or one of their subscription ids, before starting a session. Returns the customer record (attributes parsed, ICP) with the same subscription list as GET /api/v1/customers/{id}/subscriptions. An email Tenure has no record of is looked up in the connected billing provider (Stripe or Chargebee, in the mode the connection is in); a match is mirrored into Tenure through the same path as an import and returned. `source` says which answered: `mirror`, `stripe` or `chargebee`. Provider lookups have their own budget of 60 per workspace per minute (429 rate_limited, honour Retry-After); lookups the mirror answers are not counted against it.\n\nRequired scope: `read`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Customer email",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "externalId",
            "in": "query",
            "required": false,
            "description": "Your subscriber id (alias: customerId)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "subscriptionId",
            "in": "query",
            "required": false,
            "description": "Any subscription id Tenure knows for them",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "externalId": {
                      "type": "string"
                    },
                    "email": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "plan": {
                      "type": "string"
                    },
                    "icp": {
                      "type": "object",
                      "properties": {
                        "score": {
                          "type": "integer"
                        },
                        "tier": {
                          "type": "string"
                        }
                      }
                    },
                    "attributes": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "mirror",
                        "stripe",
                        "chargebee"
                      ],
                      "description": "Who answered: Tenure's own record, or the billing provider (then mirrored)."
                    },
                    "subscriptions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Subscription"
                      }
                    }
                  }
                },
                "example": {
                  "externalId": "demo_1",
                  "email": "ana@example.com",
                  "plan": "pro",
                  "source": "mirror",
                  "subscriptions": [
                    {
                      "id": "sub_123",
                      "provider": "stripe",
                      "source": "record",
                      "status": "active",
                      "plan": "pro",
                      "mrrCents": 1500
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "customer_not_found: No customer matches the given externalId/email.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "customer_not_found",
                    "message": "No customer matches the given externalId/email."
                  }
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests; honour Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many requests; honour Retry-After."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/customers/{id}/subscriptions": {
      "get": {
        "operationId": "customer_subscriptions",
        "summary": "List a customer's subscriptions",
        "description": "Every subscription Tenure can tie to the subscriber: the one on their record, ids recorded in attributes.subscriptionIds, and subscriptions observed from provider events, with the latest known status. `{id}` is your subscriber id or Tenure's customer id. Any of these ids is accepted by /subscriptions/{id}/recommended-offer and /subscriptions/{id}/cancel.\n\nRequired scope: `read`.",
        "tags": [
          "Agent"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "subscriptions"
                  ],
                  "properties": {
                    "customerId": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string",
                      "description": "Tenure's customer id."
                    },
                    "status": {
                      "type": "string"
                    },
                    "plan": {
                      "type": "string"
                    },
                    "subscriptions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Subscription"
                      }
                    }
                  }
                },
                "example": {
                  "customerId": "demo_1",
                  "id": "cus_1",
                  "status": "active",
                  "plan": "pro",
                  "subscriptions": [
                    {
                      "id": "sub_123",
                      "provider": "stripe",
                      "source": "record",
                      "status": "active",
                      "plan": "pro",
                      "mrrCents": 1500,
                      "billingInterval": "month",
                      "currentPeriodEndsAt": "2026-10-01T00:00:00.000Z",
                      "cancellationScheduled": false,
                      "endedAt": null
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "customer_not_found: No customer matches the given externalId/email.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "customer_not_found",
                    "message": "No customer matches the given externalId/email."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": true
      }
    },
    "/api/v1/events": {
      "post": {
        "operationId": "events",
        "summary": "Send lifecycle fact events",
        "description": "Send one fact or a batch of up to 100 using the decide scope. Test keys store test events and cannot write live events. Facts are checked against the confirmed app definition; unknown names are retained as unmapped. Each item has its own result. Idempotency-Key replays a batch for 24 hours; item idempotencyKey deduplicates for 30 days. X-Tenure-Source identifies the SDK (sdk-node, sdk-react, mobile-ios, mobile-android, mobile-rn, mobile-flutter, mcp, revenuecat, custom).\n\nRequired scope: `decide`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string (<=200 chars). Replays the stored response for 24h; a different body with the same key is a 409 idempotency_conflict. Replays carry `Idempotent-Replayed: true`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "subscriber",
                      "name"
                    ],
                    "properties": {
                      "subscriber": {
                        "type": "object",
                        "additionalProperties": false,
                        "anyOf": [
                          {
                            "required": [
                              "id"
                            ]
                          },
                          {
                            "required": [
                              "providerCustomerId"
                            ]
                          },
                          {
                            "required": [
                              "email"
                            ]
                          }
                        ],
                        "properties": {
                          "id": {
                            "type": "string",
                            "maxLength": 200
                          },
                          "providerCustomerId": {
                            "type": "string",
                            "maxLength": 200
                          },
                          "email": {
                            "type": "string",
                            "format": "email",
                            "maxLength": 320
                          }
                        }
                      },
                      "name": {
                        "type": "string",
                        "pattern": "^[a-z][a-z0-9_]{1,63}$"
                      },
                      "value": {
                        "type": [
                          "number",
                          "boolean",
                          "string"
                        ],
                        "maxLength": 2000
                      },
                      "occurredAt": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "idempotencyKey": {
                        "type": "string",
                        "maxLength": 200
                      },
                      "environment": {
                        "type": "string",
                        "enum": [
                          "live",
                          "test"
                        ]
                      },
                      "properties": {
                        "type": "object",
                        "maxProperties": 20,
                        "additionalProperties": {
                          "type": [
                            "string",
                            "number",
                            "boolean",
                            "null"
                          ]
                        },
                        "description": "Flat properties, at most 2 KB encoded as UTF-8 JSON."
                      }
                    }
                  },
                  {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "subscriber",
                        "name"
                      ],
                      "properties": {
                        "subscriber": {
                          "type": "object",
                          "additionalProperties": false,
                          "anyOf": [
                            {
                              "required": [
                                "id"
                              ]
                            },
                            {
                              "required": [
                                "providerCustomerId"
                              ]
                            },
                            {
                              "required": [
                                "email"
                              ]
                            }
                          ],
                          "properties": {
                            "id": {
                              "type": "string",
                              "maxLength": 200
                            },
                            "providerCustomerId": {
                              "type": "string",
                              "maxLength": 200
                            },
                            "email": {
                              "type": "string",
                              "format": "email",
                              "maxLength": 320
                            }
                          }
                        },
                        "name": {
                          "type": "string",
                          "pattern": "^[a-z][a-z0-9_]{1,63}$"
                        },
                        "value": {
                          "type": [
                            "number",
                            "boolean",
                            "string"
                          ],
                          "maxLength": 2000
                        },
                        "occurredAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "idempotencyKey": {
                          "type": "string",
                          "maxLength": 200
                        },
                        "environment": {
                          "type": "string",
                          "enum": [
                            "live",
                            "test"
                          ]
                        },
                        "properties": {
                          "type": "object",
                          "maxProperties": 20,
                          "additionalProperties": {
                            "type": [
                              "string",
                              "number",
                              "boolean",
                              "null"
                            ]
                          },
                          "description": "Flat properties, at most 2 KB encoded as UTF-8 JSON."
                        }
                      }
                    }
                  }
                ]
              },
              "example": {
                "subscriber": {
                  "id": "demo_2"
                },
                "name": "exports_completed",
                "value": 1,
                "idempotencyKey": "export-123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "received": {
                      "type": [
                        "integer",
                        "boolean"
                      ]
                    },
                    "stored": {
                      "type": "integer"
                    },
                    "unmapped": {
                      "type": "integer"
                    },
                    "rejected": {
                      "type": "integer"
                    },
                    "environment": {
                      "enum": [
                        "live",
                        "test"
                      ]
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "index": {
                            "type": "integer"
                          },
                          "status": {
                            "enum": [
                              "stored",
                              "duplicate",
                              "unmapped",
                              "rejected"
                            ]
                          },
                          "eventId": {
                            "type": "string"
                          },
                          "fact": {
                            "type": "string"
                          },
                          "error": {
                            "type": "object"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "received": 1,
                  "stored": 1,
                  "unmapped": 0,
                  "rejected": 0,
                  "environment": "test",
                  "results": [
                    {
                      "index": 0,
                      "status": "stored",
                      "eventId": "event_123",
                      "fact": "exports_completed"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "environment_mismatch: The key or subscriber cannot write to the requested environment.; scope_denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "409": {
            "description": "idempotency_conflict: The same Idempotency-Key was reused with a different request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "idempotency_conflict",
                    "message": "The same Idempotency-Key was reused with a different request body."
                  }
                }
              }
            }
          },
          "413": {
            "description": "batch_too_large: Send at most 100 lifecycle fact events per batch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "batch_too_large",
                    "message": "Send at most 100 lifecycle fact events per batch."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/telemetry/heartbeat": {
      "post": {
        "operationId": "telemetry_heartbeat",
        "summary": "Report independent server telemetry health",
        "description": "An independent server collector or scheduler reports healthy, degraded or down even when product usage is zero. This never creates product usage. First acceptance enrolls the source; thereafter stale or negative reports hold applicable proactive actions. Existing sources are not enrolled automatically. Authentication determines workspace and test/live environment; public widget keys and body scope overrides are not accepted. Persist a sequence across sender restarts; identical latest payload replays do not refresh health. Conflicting/old sequences, regressed timestamps, excessive future skew or a changed cadence return 409 revision_conflict. See /docs/telemetry-heartbeat.\n\nRequired scope: `decide`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "sourceKey",
                  "sequence",
                  "observedAt",
                  "status",
                  "cadenceSeconds"
                ],
                "properties": {
                  "sourceKey": {
                    "type": "string",
                    "maxLength": 180,
                    "pattern": "^(product-events|event:[a-z][a-z0-9_]{2,47}|(?:customer_data|usage):[a-zA-Z0-9_-]+)$",
                    "description": "product-events covers the direct host stream; event:<technicalName> requires a current confirmed enabled event fact. customer_data:<sourceId> and usage:<sourceId> must belong to this workspace and the authenticated environment."
                  },
                  "sequence": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 9007199254740991,
                    "description": "Durable increasing counter per source and environment; preserve it across sender restarts. Only an identical latest sequence and payload is an idempotent replay."
                  },
                  "observedAt": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Time of the independent server health check. New sequences must advance observation time. Future skew above 15 seconds is rejected; accepted future skew never extends the deadline past server receipt plus three cadences."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "healthy",
                      "degraded",
                      "down"
                    ]
                  },
                  "cadenceSeconds": {
                    "type": "integer",
                    "minimum": 30,
                    "maximum": 3600,
                    "description": "Expected cadence, fixed on first enrollment. Health expires exactly three cadences after the observation, bounded by receipt time."
                  }
                }
              },
              "example": {
                "sourceKey": "event:exports_completed",
                "sequence": 42,
                "observedAt": "2026-10-10T15:00:00Z",
                "status": "healthy",
                "cadenceSeconds": 60
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "accepted",
                    "duplicate",
                    "freshUntil",
                    "version"
                  ],
                  "properties": {
                    "accepted": {
                      "type": "boolean",
                      "const": true,
                      "description": "The report was recorded; this does not authorize a proactive action."
                    },
                    "duplicate": {
                      "type": "boolean",
                      "description": "An identical replay; freshness was not extended."
                    },
                    "freshUntil": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "version": {
                      "type": "string",
                      "description": "Opaque health generation, stable during continuous healthy cadence and changed by negative health or a missed heartbeat window."
                    }
                  }
                },
                "example": {
                  "accepted": true,
                  "duplicate": false,
                  "freshUntil": "2026-10-10T15:03:00Z",
                  "version": "heartbeat_123:1"
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.; bad_json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_json",
                    "message": "The request body is not valid JSON."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.; key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "key_expired",
                    "message": "The API key's expiresAt is in the past."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "not_found: The resource does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "The resource does not exist."
                  }
                }
              }
            }
          },
          "409": {
            "description": "revision_conflict: The resource changed since it was read. Reload its revision before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "revision_conflict",
                    "message": "The resource changed since it was read. Reload its revision before retrying."
                  }
                }
              }
            }
          },
          "413": {
            "description": "payload_too_large: The request body is larger than this endpoint accepts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "payload_too_large",
                    "message": "The request body is larger than this endpoint accepts."
                  }
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Unexpected server error; quote `ref` when reporting it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal_error",
                    "message": "Unexpected server error; quote `ref` when reporting it."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/customers": {
      "post": {
        "operationId": "customers_upsert",
        "summary": "Upsert customers",
        "description": "One customer object or an array (max 500). All writes in the request are atomic; a failure rolls back earlier writes. Repeated external IDs apply in request order. This is how the host syncs plan, MRR, tenure, amount paid to date (ltvCents) and usage facts.\n\nRequired scope: `decide`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Customer"
                  },
                  {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/Customer"
                    },
                    "maxItems": 500
                  }
                ]
              },
              "example": {
                "externalId": "demo_1",
                "email": "ana@example.com",
                "plan": "pro",
                "mrrCents": 1500,
                "tenureMonths": 14
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "upserted": {
                      "type": "integer"
                    },
                    "customers": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "externalId": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "upserted": 1,
                  "customers": [
                    {
                      "id": "cus_1",
                      "externalId": "demo_1"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      },
      "get": {
        "operationId": "customers_get",
        "summary": "Get a customer or list recent",
        "description": "With `externalId` returns the facts on one customer; without it, the 100 most recently updated. No score is computed.\n\nRequired scope: `read`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "externalId",
            "in": "query",
            "required": false,
            "description": "Your subscriber id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                },
                "example": {
                  "externalId": "demo_1",
                  "plan": "pro",
                  "mrrCents": 1500,
                  "tenureMonths": 14,
                  "status": "active",
                  "attributes": {}
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "not_found: The resource does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "The resource does not exist."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/sessions/aggregate": {
      "get": {
        "operationId": "sessions_aggregate",
        "summary": "Aggregate sessions across dimensions",
        "description": "Uses the session-list filters, excluding cursor and limit. breakdown accepts 1–4 comma- or hyphen-separated dimensions: day, week, month, status, surface, reason, arm, variant, offerType, saveType, plan, planId, billingInterval, trial, currency. Calendar buckets use UTC; weeks start Monday. Subscription dimensions are historical; unknown values group as null. saveType uses Tenure's session result vocabulary. Counts include all matching rows.\n\nRequired scope: `read`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "trial",
            "in": "query",
            "required": false,
            "description": "Trial status captured at session creation. Unknown/legacy facts match neither true nor false.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "billingInterval",
            "in": "query",
            "required": false,
            "description": "Captured billing interval: DAY, WEEK, MONTH, YEAR; comma-separated. Case-insensitive.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "planId",
            "in": "query",
            "required": false,
            "description": "Captured provider plan/price ID, comma-separated; unknown or ambiguous IDs do not match.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Comma-separated: OPEN, ACCEPTED, DECLINED, CANCELLED, ABANDONED, PASSED, EXPIRED, RESOLVING, FULFILLING, ESCALATED",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "customerId",
            "in": "query",
            "required": false,
            "description": "Your subscriber id (exact match)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plan",
            "in": "query",
            "required": false,
            "description": "Customer plan(s), comma-separated",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offerType",
            "in": "query",
            "required": false,
            "description": "Kind of the published offer the session presented, comma-separated: pause, discount, downgrade, extension, credit, talk_to_founder",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "reason",
            "in": "query",
            "required": false,
            "description": "Cancel reason id(s): too_expensive, not_using, missing_features, found_alternative, technical_issues, temporary, completed, other",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "surface",
            "in": "query",
            "required": false,
            "description": "WIDGET, HOSTED or API (host-rendered and AI-agent attempts)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "variant",
            "in": "query",
            "required": false,
            "description": "Experiment variant, e.g. A or B",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "arm",
            "in": "query",
            "required": false,
            "description": "TREATMENT, HOLDOUT or INELIGIBLE",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "executionStatus",
            "in": "query",
            "required": false,
            "description": "NONE, PENDING, RESERVED, DONE, HOST, UNAPPLIED or FAILED",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "Language the flow was shown in; a bare language (`es`) also matches regional tags (`es-MX`). Malformed tags return 400.",
            "schema": {
              "type": "string",
              "maxLength": 16,
              "pattern": "^[A-Za-z]{2,3}(-[A-Za-z0-9]{1,8})*$"
            }
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Visitor region: a country (`US`, also matching `US-CA`) or a region (`US-CA`). Malformed values return 400.",
            "schema": {
              "type": "string",
              "maxLength": 8,
              "pattern": "^[A-Za-z]{2}(-[A-Za-z0-9]{1,3})?$"
            }
          },
          {
            "name": "usedClickToCancel",
            "in": "query",
            "required": false,
            "description": "true: only sessions that ended with the one-click cancel button; false: only those that didn't",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "includeBounced",
            "in": "query",
            "required": false,
            "description": "true keeps sessions that closed within seconds without an interaction (default false).",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "includeTest",
            "in": "query",
            "required": false,
            "description": "true includes test-mode sessions (default false). A test key always gets test sessions of test subscribers only.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "saveType",
            "in": "query",
            "required": false,
            "description": "Session result(s), comma-separated: saved, not_applied, cancelled, abandoned, superseded, expired, escalated, open. The same vocabulary as `session.result` and the aggregate's saveType dimension.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "ISO date/time, inclusive (`createdAt >=`).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "ISO date/time, exclusive (`createdAt <`); a bare date means midnight UTC at the start of that date, so `from=2026-09-01&to=2026-09-01` is an empty window -- ask for a whole day as `from=2026-09-01&to=2026-09-02`. This is a timestamp feed, so consecutive pulls meet exactly and never overlap; /api/v1/metrics is a day report and its `to` is an inclusive calendar day instead.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "breakdown",
            "in": "query",
            "required": false,
            "description": "1–4 dimensions; default month",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "breakdown": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "timezone": {
                      "type": "string",
                      "const": "UTC"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "rows": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "count": {
                            "type": "integer"
                          }
                        },
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/sessions": {
      "get": {
        "operationId": "sessions_list",
        "summary": "List cancel sessions",
        "description": "Cursor-paginated, newest first. Every list filter accepts comma-separated values and they AND together. Bounced sessions (closed within seconds without an interaction) and test sessions are excluded unless you ask for them. `saveType` filters on `session.result`. `from`/`to` are the date parameters.\n\nRequired scope: `read`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "trial",
            "in": "query",
            "required": false,
            "description": "Trial status captured at session creation. Unknown/legacy facts match neither true nor false.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "billingInterval",
            "in": "query",
            "required": false,
            "description": "Captured billing interval: DAY, WEEK, MONTH, YEAR; comma-separated. Case-insensitive.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "planId",
            "in": "query",
            "required": false,
            "description": "Captured provider plan/price ID, comma-separated; unknown or ambiguous IDs do not match.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Comma-separated: OPEN, ACCEPTED, DECLINED, CANCELLED, ABANDONED, PASSED, EXPIRED, RESOLVING, FULFILLING, ESCALATED",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "customerId",
            "in": "query",
            "required": false,
            "description": "Your subscriber id (exact match)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plan",
            "in": "query",
            "required": false,
            "description": "Customer plan(s), comma-separated",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offerType",
            "in": "query",
            "required": false,
            "description": "Kind of the published offer the session presented, comma-separated: pause, discount, downgrade, extension, credit, talk_to_founder",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "reason",
            "in": "query",
            "required": false,
            "description": "Cancel reason id(s): too_expensive, not_using, missing_features, found_alternative, technical_issues, temporary, completed, other",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "surface",
            "in": "query",
            "required": false,
            "description": "WIDGET, HOSTED or API (host-rendered and AI-agent attempts)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "variant",
            "in": "query",
            "required": false,
            "description": "Experiment variant, e.g. A or B",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "arm",
            "in": "query",
            "required": false,
            "description": "TREATMENT, HOLDOUT or INELIGIBLE",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "executionStatus",
            "in": "query",
            "required": false,
            "description": "NONE, PENDING, RESERVED, DONE, HOST, UNAPPLIED or FAILED",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "Language the flow was shown in; a bare language (`es`) also matches regional tags (`es-MX`). Malformed tags return 400.",
            "schema": {
              "type": "string",
              "maxLength": 16,
              "pattern": "^[A-Za-z]{2,3}(-[A-Za-z0-9]{1,8})*$"
            }
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Visitor region: a country (`US`, also matching `US-CA`) or a region (`US-CA`). Malformed values return 400.",
            "schema": {
              "type": "string",
              "maxLength": 8,
              "pattern": "^[A-Za-z]{2}(-[A-Za-z0-9]{1,3})?$"
            }
          },
          {
            "name": "usedClickToCancel",
            "in": "query",
            "required": false,
            "description": "true: only sessions that ended with the one-click cancel button; false: only those that didn't",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "includeBounced",
            "in": "query",
            "required": false,
            "description": "true keeps sessions that closed within seconds without an interaction (default false).",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "includeTest",
            "in": "query",
            "required": false,
            "description": "true includes test-mode sessions (default false). A test key always gets test sessions of test subscribers only.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "saveType",
            "in": "query",
            "required": false,
            "description": "Session result(s), comma-separated: saved, not_applied, cancelled, abandoned, superseded, expired, escalated, open. The same vocabulary as `session.result` and the aggregate's saveType dimension.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "ISO date/time, inclusive (`createdAt >=`).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "ISO date/time, exclusive (`createdAt <`); a bare date means midnight UTC at the start of that date, so `from=2026-09-01&to=2026-09-01` is an empty window -- ask for a whole day as `from=2026-09-01&to=2026-09-02`. This is a timestamp feed, so consecutive pulls meet exactly and never overlap; /api/v1/metrics is a day report and its `to` is an inclusive calendar day instead.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "nextCursor from the previous page",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-200, default 50",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "sessions",
                    "hasMore"
                  ],
                  "properties": {
                    "sessions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SessionSummary"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass back as `cursor` for the next page; null on the last page."
                    },
                    "hasMore": {
                      "type": "boolean"
                    }
                  }
                },
                "example": {
                  "sessions": [
                    {
                      "id": "cmf1abc",
                      "customerId": "demo_1",
                      "plan": "pro",
                      "surface": "WIDGET",
                      "status": "ACCEPTED",
                      "executionStatus": "DONE",
                      "arm": "TREATMENT",
                      "variant": "A",
                      "reason": "too_expensive",
                      "reasonText": "It costs more than my whole stack",
                      "bounced": false,
                      "offer": {
                        "id": "row_disc20",
                        "kind": "discount"
                      },
                      "presentedOffers": [
                        {
                          "rowId": "row_disc20",
                          "kind": "discount",
                          "termsRef": "row:row_disc20:3f9a",
                          "presentedAt": "2026-09-10T10:00:00.000Z",
                          "acceptedAt": null,
                          "declinedAt": null
                        }
                      ],
                      "savedMrrCents": 1500,
                      "createdAt": "2026-09-10T10:00:00.000Z",
                      "resolvedAt": "2026-09-10T10:01:00.000Z"
                    }
                  ],
                  "nextCursor": null,
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/sessions/{id}": {
      "get": {
        "operationId": "session_get",
        "summary": "Get a cancel session",
        "description": "Full session record: status, offer, execution log, platform and conversationId, with every SessionBlock field (the same block webhooks carry) and `customer` as the CustomerBlock. `{id}` is a Tenure session id or your own `X-Session-Id`, and the `chain` block is the same compact view the session-chain endpoints return.\n\nRequired scope: `read`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "type": "object",
                      "description": "A cancel session (full record).",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string"
                        },
                        "executionStatus": {
                          "type": "string"
                        },
                        "surface": {
                          "type": "string"
                        },
                        "platform": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "conversationId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "isTest": {
                          "type": "boolean"
                        },
                        "reason": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "arm": {
                          "type": "string"
                        },
                        "executionLog": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "savedMrrCents": {
                          "type": "integer",
                          "description": "The monthly value kept, recorded when billing confirmed the save (cents); 0 for a pause or no save. A recorded run-rate, not money collected."
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "resolvedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        }
                      },
                      "additionalProperties": true
                    },
                    {
                      "$ref": "#/components/schemas/SessionBlock"
                    }
                  ],
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/CustomerBlock"
                    },
                    "offerTerms": {
                      "$ref": "#/components/schemas/OfferTerms"
                    },
                    "chain": {
                      "$ref": "#/components/schemas/ChainSession"
                    }
                  }
                },
                "example": {
                  "id": "cmf1abc",
                  "status": "ACCEPTED",
                  "executionStatus": "DONE",
                  "platform": "intercom_fin",
                  "conversationId": "conv_8213",
                  "savedMrrCents": 1500
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "404": {
            "description": "not_found: The resource does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "The resource does not exist."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/metrics": {
      "get": {
        "operationId": "metrics",
        "summary": "Results figures",
        "description": "The figures Results shows, for a warehouse or a BI tool, from the same readers as Results and the weekly email: customer moments (also by moment type), billing offers accepted at every moment (`accepted`, `acceptedBillingOffer`) and, at cancel clicks, offers taken that billing confirmed (`tookOffer`, the count Results and Overview show; a change waiting for its renewal is not one yet), and requests to talk (separately; `askedToTalk` counts customers waiting on your reply, a to-do rather than an outcome), billing changes confirmed, revenue kept (paid save invoices after refunds, as Overview shows it; a save not invoiced yet is `money.keptAtAcceptance`), offer cost and each other ledger line on its own, whether cancellation saves lasted, and how many customer moments came with the customer's own words. Every number is a Figure with its kind, value and n; a rate below the minimum denominator has a null value and only its counts. Simulated activity is never included. To compare periods, call once per period.\n\nRequired scope: `read`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "ISO date, inclusive. With `to`, overrides `days`.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "ISO date, inclusive: the whole of that UTC day is counted, so `from=2026-09-01&to=2026-09-01` is one day. (`range.to` in the response is the exclusive instant this day ends at.) At most 366 days.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Trailing window when from/to are absent: the last 7, 30 (default) or 90 × 24 hours up to now, the window Results calls Last N days.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "env",
            "in": "query",
            "required": false,
            "description": "live or test; defaults to the key's mode.",
            "schema": {
              "type": "string",
              "enum": [
                "live",
                "test"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "range",
                    "environment",
                    "currency",
                    "figures"
                  ],
                  "properties": {
                    "range": {
                      "type": "object",
                      "properties": {
                        "from": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "to": {
                          "type": "string",
                          "format": "date-time",
                          "description": "Exclusive."
                        }
                      }
                    },
                    "environment": {
                      "type": "string",
                      "enum": [
                        "live",
                        "test"
                      ]
                    },
                    "currency": {
                      "type": "string"
                    },
                    "figures": {
                      "type": "object",
                      "description": "Every number is a Figure. Money lines are never summed across kinds.",
                      "properties": {
                        "moments": {
                          "$ref": "#/components/schemas/Figure"
                        },
                        "byType": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "type": {
                                "type": "string"
                              },
                              "label": {
                                "type": "string"
                              },
                              "moments": {
                                "$ref": "#/components/schemas/Figure"
                              },
                              "accepted": {
                                "$ref": "#/components/schemas/Figure"
                              }
                            }
                          }
                        },
                        "decided": {
                          "type": "object",
                          "additionalProperties": {
                            "$ref": "#/components/schemas/Figure"
                          },
                          "description": "offer, nothing, askedYou, previewOnly"
                        },
                        "responses": {
                          "type": "object",
                          "additionalProperties": {
                            "$ref": "#/components/schemas/Figure"
                          },
                          "description": "sent, delivered, clicked, dismissed"
                        },
                        "accepted": {
                          "$ref": "#/components/schemas/Figure"
                        },
                        "confirmed": {
                          "$ref": "#/components/schemas/Figure"
                        },
                        "money": {
                          "type": "object",
                          "additionalProperties": {
                            "$ref": "#/components/schemas/Figure"
                          },
                          "description": "kept, offerCost, expansion, returned, pauseCollected (observed) and linked (attributed)"
                        },
                        "awaitingAmount": {
                          "$ref": "#/components/schemas/Figure"
                        },
                        "lasting": {
                          "type": "object",
                          "additionalProperties": {
                            "$ref": "#/components/schemas/Figure"
                          },
                          "description": "saves, stillSubscribed, tooEarly, notCheckable, leftWithinOneCycle"
                        },
                        "words": {
                          "type": "object",
                          "properties": {
                            "moments": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "groups": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "label": {
                                    "type": "string"
                                  },
                                  "moments": {
                                    "$ref": "#/components/schemas/Figure"
                                  }
                                }
                              }
                            }
                          }
                        },
                        "forecast": {
                          "type": "object",
                          "description": "Offers accepted in the range that came with a forecast: followed, matched, immature, noInvoice, notConfirmed, otherCurrency (observed counts; the last five add up to followed), and compared: null until a forecast period has ended with an invoice recorded, then assumptionVersions and collected, expansion, refunded, offerCost (observed), forecastRevenue, forecastOfferCost, revenueDifference, offerCostDifference (modeled) and profit (withheld: no_matched_cost). A check of forecasts against billing, not a measure of what the offers changed.",
                          "properties": {
                            "followed": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "matched": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "immature": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "noInvoice": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "notConfirmed": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "otherCurrency": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "compared": {
                              "type": [
                                "object",
                                "null"
                              ],
                              "properties": {
                                "assumptionVersions": {
                                  "type": "string"
                                }
                              },
                              "additionalProperties": {
                                "$ref": "#/components/schemas/Figure"
                              }
                            }
                          }
                        },
                        "byReason": {
                          "type": "object",
                          "description": "Why people leave: cancel clicks in the range by the reason picked (key, label; key \"none\" when none was picked), each with moments and previous (the equal period before, previousRange), accepted (rate over the reason's moments), confirmed, cancelled, noOffer and shown (offers shown: rowId, label, shown). wrote counts the cancel clicks that came with written words; themed and unthemed split those by whether the words were given a theme (themes need AI: without it, or with the month's AI allowance spent, words stay unthemed); themes (theme, label, moments) counts each cancel click once under every theme its words carry, so they can add up to more than themed. Offers applied by hand are left out. All observed.",
                          "properties": {
                            "previousRange": {
                              "type": "object",
                              "properties": {
                                "from": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "to": {
                                  "type": "string",
                                  "format": "date-time"
                                }
                              }
                            },
                            "moments": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "previous": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "reasons": {
                              "type": "array",
                              "items": {
                                "type": "object"
                              }
                            },
                            "wrote": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "themed": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "unthemed": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "themes": {
                              "type": "array",
                              "items": {
                                "type": "object"
                              }
                            }
                          }
                        },
                        "byRow": {
                          "type": "object",
                          "description": "How each offer did: lines (key, label: the experience and the policy title, momentType, preview: the line runs Preview only) of published plan rows, the cancel option left out (rowId, label, rowType, published, changesBilling) with shown, accepted (counts of customer moments), confirmed (rate over accepted offers that change billing), stillSubscribed (rate over cancellation saves one billing period on), tooEarly, cost (money) and wouldHave (customer moments a Preview only decision would have offered it to). An extra-usage row (rowType usage_credit) counts its promises: accepted is the promises made, confirmed the share added, and extraUsage gives promised, added, notGiven, waiting and cancelledFirst (null on every other row). Rows decided in the range that are no longer published come last under key \"earlier\". All observed.",
                          "properties": {
                            "lines": {
                              "type": "array",
                              "items": {
                                "type": "object"
                              }
                            }
                          }
                        },
                        "tenureCost": {
                          "type": "object",
                          "description": "What Tenure's decision model used for the range's moments: calls, withoutTokens, inputTokens (observed) and modelCost (modeled at the deployment's rate; null when the deployment sets none). Tenure's price is never included (priceIncluded: false).",
                          "properties": {
                            "calls": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "withoutTokens": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "inputTokens": {
                              "$ref": "#/components/schemas/Figure"
                            },
                            "modelCost": {
                              "oneOf": [
                                {
                                  "$ref": "#/components/schemas/Figure"
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "priceIncluded": {
                              "type": "boolean",
                              "const": false
                            }
                          }
                        },
                        "coverage": {
                          "type": "object",
                          "additionalProperties": {
                            "$ref": "#/components/schemas/Figure"
                          },
                          "description": "billing: cancellations Stripe or Chargebee recorded in the range, leaving out those billing made after failed payments (parts by provider); reached: the ones that went through a Tenure cancel attempt first; neverReached: the rest (parts by provider). All observed counts."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "range": {
                    "from": "2026-09-07T00:00:00.000Z",
                    "to": "2026-09-14T00:00:00.000Z"
                  },
                  "environment": "live",
                  "currency": "usd",
                  "figures": {
                    "moments": {
                      "label": "Eligible moments",
                      "kind": "observed",
                      "unit": "count",
                      "value": 42,
                      "n": 42,
                      "of": null
                    },
                    "accepted": {
                      "label": "Accepted a billing offer",
                      "kind": "observed",
                      "unit": "rate",
                      "value": 0.143,
                      "numerator": 6,
                      "n": 42,
                      "of": "eligible_moments",
                      "interval": {
                        "lower": 0.067,
                        "upper": 0.278
                      }
                    },
                    "acceptedBillingOffer": {
                      "label": "Accepted a billing offer",
                      "kind": "observed",
                      "unit": "count",
                      "value": 6,
                      "n": 6,
                      "of": null
                    },
                    "tookOffer": {
                      "label": "Took an offer",
                      "kind": "observed",
                      "unit": "count",
                      "value": 5,
                      "n": 5,
                      "of": null
                    },
                    "askedToTalk": {
                      "label": "Asked to talk",
                      "kind": "observed",
                      "unit": "count",
                      "value": 2,
                      "n": 2,
                      "of": null
                    },
                    "money": {
                      "kept": {
                        "label": "Collected from saves, after recorded refunds",
                        "kind": "observed",
                        "unit": "money",
                        "value": 17400,
                        "currency": "usd",
                        "n": 6,
                        "of": "accepted",
                        "sourceTransactions": 6
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/cancel-sessions": {
      "post": {
        "operationId": "cancel_sessions_create",
        "summary": "Mint a hosted cancel link",
        "description": "Creates a one-off link to the hosted cancel flow for a customer you already sync, so support tools and emails can hand someone a page that knows who they are without any signing code. A single-use link is used up when the customer's page first acts on it, not when it is opened, so mail scanners that open every link in a message do not spend it; once used, or expired, it shows an explanatory page (with the email-verification fallback when that is enabled).\n\nRequired scope: `decide`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Identify the customer by customerId or email; the customer must already exist (POST /api/v1/customers).",
                "properties": {
                  "customerId": {
                    "type": "string",
                    "description": "Your subscriber id."
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "subscriptionId": {
                    "type": "string",
                    "description": "Carried into the flow when a customer has several subscriptions."
                  },
                  "expiresAt": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Default 24 hours from now (the workspace's hosted link lifetime under Hosted page settings), at most 30 days out. The app library's identity token is separate and lasts one hour."
                  },
                  "singleUse": {
                    "type": "boolean",
                    "default": true,
                    "description": "true consumes the link on first open."
                  },
                  "returnUrl": {
                    "type": "string",
                    "description": "Absolute URL to send the customer back to; ?tenure=saved|cancelled|closed is appended (the parameter name is historical, and is what every shipped client reads)."
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "live",
                      "test"
                    ]
                  }
                }
              },
              "example": {
                "customerId": "demo_1",
                "expiresAt": "2026-09-11T10:00:00Z",
                "singleUse": true,
                "returnUrl": "https://acme.example/account"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "url",
                    "token",
                    "expiresAt"
                  ],
                  "properties": {
                    "url": {
                      "type": "string",
                      "description": "Give this to the customer."
                    },
                    "token": {
                      "type": "string"
                    },
                    "expiresAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "customerId": {
                      "type": "string"
                    },
                    "subscriptionId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "singleUse": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string",
                      "const": "active"
                    }
                  }
                },
                "example": {
                  "url": "https://app.example.com/c/pk_live_abc?link=cl_9f2…&return=https%3A%2F%2Facme.example%2Faccount",
                  "token": "cl_9f2…",
                  "expiresAt": "2026-09-11T10:00:00.000Z",
                  "customerId": "demo_1",
                  "singleUse": true,
                  "status": "active"
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.; bad_json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_json",
                    "message": "The request body is not valid JSON."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "customer_not_found: No customer matches the given externalId/email.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "customer_not_found",
                    "message": "No customer matches the given externalId/email."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/export": {
      "get": {
        "operationId": "export",
        "summary": "Export data for a warehouse",
        "description": "Warehouse export. With no dataset, or dataset=attempts: a CSV of cancel sessions created since `since`. dataset=ledger or dataset=decisions: the Results export CSVs (financial records, or one row per customer moment at its current decision) for one environment and period; the file starts with its header row (since 13 Oct 2026; before, a `#` note came first), amounts are integers in the currency's minor unit, and customers appear by id, external id and masked email. records=<type>: newline-delimited JSON of one lifecycle record type changed since `since`; deliveries carry no message text, recipient or link tokens.\n\nRequired scope: `read`.",
        "tags": [
          "Data"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Inclusive ISO calendar date or timestamp; impossible dates and empty values return 400. For records, rows changed since then",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dataset",
            "in": "query",
            "required": false,
            "description": "attempts (default), ledger or decisions",
            "schema": {
              "type": "string",
              "enum": [
                "attempts",
                "ledger",
                "decisions"
              ]
            }
          },
          {
            "name": "records",
            "in": "query",
            "required": false,
            "description": "One lifecycle record type as NDJSON; not with dataset",
            "schema": {
              "type": "string",
              "enum": [
                "moments",
                "decisions",
                "approvals",
                "executions",
                "deliveries",
                "ledgerEntries",
                "planSnapshots",
                "sharedLimitsVersions",
                "forecasts",
                "outcomes",
                "momentTexts",
                "billingHistory",
                "billingHistoryInvoices"
              ]
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "ledger and decisions: exclusive end of the period, ISO date or timestamp (default now)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "env",
            "in": "query",
            "required": false,
            "description": "ledger and decisions: live (default) or test. records: live, test or simulated (default all)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moment",
            "in": "query",
            "required": false,
            "description": "ledger and decisions: only this customer moment type",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/dsr": {
      "get": {
        "operationId": "dsr_get",
        "summary": "Data-subject access",
        "description": "Everything held about one customer (by externalId or email), with a `counts` block per collection so you can show the subject what exists. Includes their moments, decisions, approvals, executions, ledger entries, forecasts and outcomes. Refunds issued to the subject and the billing identities held for them are included. Includes stored product events and subscription observations linked to this local customer. Observations preserve provider/site, live or test mode, event time and recorded termination facts; unlinked historical events are not included. Customer fields reflect the current synchronized record. Logged as dsr.export.\n\nRequired scope: `read`.",
        "tags": [
          "Compliance"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "externalId",
            "in": "query",
            "required": false,
            "description": "Your subscriber id",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Customer email. Matched without regard to letter case or surrounding space; when two subscribers share the address in different case the request is refused (validation_error) and each must be requested by externalId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "counts": {
                      "type": "object",
                      "description": "Rows held per collection.",
                      "additionalProperties": {
                        "type": "integer"
                      }
                    },
                    "customer": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "sessions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "invoices": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "productEvents": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "refunds": {
                      "type": "array",
                      "description": "Refunds issued to this subject: amount, currency, reason, provider references, status and dates.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "billingIdentities": {
                      "type": "array",
                      "description": "Provider records tied to this subject (provider and remote id).",
                      "items": {
                        "type": "object",
                        "properties": {
                          "provider": {
                            "type": "string"
                          },
                          "remoteId": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "subscriptionObservations": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "provider": {
                            "type": "string",
                            "enum": [
                              "stripe",
                              "chargebee"
                            ]
                          },
                          "providerSite": {
                            "type": "string"
                          },
                          "billingMode": {
                            "type": "string",
                            "enum": [
                              "live",
                              "test"
                            ]
                          },
                          "eventId": {
                            "type": "string"
                          },
                          "subscriptionId": {
                            "type": "string"
                          },
                          "customerId": {
                            "type": "string",
                            "description": "Provider customer ID."
                          },
                          "eventAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "observedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "status": {
                            "type": "string"
                          },
                          "endedAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "cancellationScheduled": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "counts": {
                    "sessions": 3,
                    "events": 41,
                    "invoices": 12,
                    "hostedLinks": 1,
                    "verificationCodes": 0,
                    "webhookDeliveries": 6,
                    "productEvents": 0,
                    "subscriptionObservations": 0,
                    "refunds": 0,
                    "billingIdentities": 0
                  },
                  "customer": {
                    "externalId": "demo_1"
                  },
                  "sessions": [],
                  "invoices": [],
                  "productEvents": [],
                  "subscriptionObservations": []
                }
              }
            }
          },
          "400": {
            "description": "validation_error: The request body or query failed validation. message lists the fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_error",
                    "message": "The request body or query failed validation. message lists the fields."
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          },
          "403": {
            "description": "scope_denied: The API key does not carry the scope this operation needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "scope_denied",
                    "message": "The API key does not carry the scope this operation needs."
                  }
                }
              }
            }
          },
          "404": {
            "description": "not_found: The resource does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "The resource does not exist."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/config/{publicKey}": {
      "get": {
        "operationId": "config",
        "summary": "Public widget config",
        "description": "Public, cacheable flow configuration for the embeddable widget (no auth; keyed by the workspace's public key).",
        "tags": [
          "Public"
        ],
        "security": [],
        "parameters": [
          {
            "name": "publicKey",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "orgName": {
                      "type": "string"
                    },
                    "reasons": {
                      "type": "array"
                    },
                    "flow": {
                      "type": "object"
                    },
                    "locale": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "orgName": "Acme Streaming",
                  "locale": "en-US"
                }
              }
            }
          },
          "404": {
            "description": "not_found: The resource does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "The resource does not exist."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    },
    "/api/v1/oauth/token": {
      "post": {
        "operationId": "oauth_token",
        "summary": "OAuth client-credentials token",
        "description": "Shim for OAuth-only agent platforms: grant_type=client_credentials, client_id = key prefix, client_secret = API key. Returns the API key as the bearer token (form-encoded or JSON body; HTTP Basic also accepted).",
        "tags": [
          "Auth"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type",
                  "client_secret"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "const": "client_credentials"
                  },
                  "client_id": {
                    "type": "string"
                  },
                  "client_secret": {
                    "type": "string"
                  },
                  "scope": {
                    "type": "string",
                    "description": "Optional space-separated exact set of the key's scopes. This API-key exchange cannot narrow permissions; a subset returns invalid_scope."
                  }
                }
              },
              "example": {
                "grant_type": "client_credentials",
                "client_id": "ck_live_AQtLKXi",
                "client_secret": "ck_live_..."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "access_token": {
                      "type": "string"
                    },
                    "token_type": {
                      "type": "string",
                      "const": "Bearer"
                    },
                    "expires_in": {
                      "type": "integer"
                    },
                    "scope": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "access_token": "ck_live_...",
                  "token_type": "Bearer",
                  "expires_in": 31536000,
                  "scope": "read decide"
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: Missing, unknown or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "Missing, unknown or revoked API key."
                  }
                }
              }
            }
          }
        },
        "x-agent-tool": false
      }
    }
  },
  "webhooks": {
    "session.completed": {
      "post": {
        "summary": "A session finished, whatever the outcome (saved, not applied, cancelled, declined, abandoned, superseded, expired, recovered, not recovered). Informational: never apply billing from it. Test mode included when the workspace turns on Send test-mode events.",
        "description": "A session finished, whatever the outcome (saved, not applied, cancelled, declined, abandoned, superseded, expired, recovered, not recovered). Informational: never apply billing from it. Test mode included when the workspace turns on Send test-mode events. Signed with x-tenure-signature over \"<x-tenure-timestamp>.<raw body>\".",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received. Answer { ok, reference } for fulfilment events (cancel.confirmed, entitlement.grant), and { ok: true, grantId } for usage.grant."
          }
        }
      }
    },
    "offer.accepted": {
      "post": {
        "summary": "An offer was accepted (any moment type; by the customer, or applied by hand by a founder) and its billing change has its first outcome: `execution.status` is confirmed, awaiting_confirmation, failed or simulated (test only). One per acceptance; a win-back return the card refused (`failed`) that succeeds on a later try sends one more, for the same execution, with its new status. Informational: Tenure already carried out the change; never apply billing from it. Test mode included when the workspace turns on Send test-mode events.",
        "description": "An offer was accepted (any moment type; by the customer, or applied by hand by a founder) and its billing change has its first outcome: `execution.status` is confirmed, awaiting_confirmation, failed or simulated (test only). One per acceptance; a win-back return the card refused (`failed`) that succeeds on a later try sends one more, for the same execution, with its new status. Informational: Tenure already carried out the change; never apply billing from it. Test mode included when the workspace turns on Send test-mode events. Signed with x-tenure-signature over \"<x-tenure-timestamp>.<raw body>\".",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received. Answer { ok, reference } for fulfilment events (cancel.confirmed, entitlement.grant), and { ok: true, grantId } for usage.grant."
          }
        }
      }
    },
    "usage.grant": {
      "post": {
        "summary": "A customer accepted extra usage your backend adds (delivered through the webhook, never through billing). Fulfilment: add `grant.units` of `grant.unit` once per `grant.grantId`, then answer 2xx with { ok: true, grantId: <grant.grantId> }. Nothing else confirms it: a bare 2xx or { ok: true } alone is unacknowledged, and after two hours the customer is told the units couldn't be added. `test: true` marks the Send a test grant request. Never sent to the events-only endpoint.",
        "description": "A customer accepted extra usage your backend adds (delivered through the webhook, never through billing). Fulfilment: add `grant.units` of `grant.unit` once per `grant.grantId`, then answer 2xx with { ok: true, grantId: <grant.grantId> }. Nothing else confirms it: a bare 2xx or { ok: true } alone is unacknowledged, and after two hours the customer is told the units couldn't be added. `test: true` marks the Send a test grant request. Never sent to the events-only endpoint. Signed with x-tenure-signature over \"<x-tenure-timestamp>.<raw body>\".",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received. Answer { ok, reference } for fulfilment events (cancel.confirmed, entitlement.grant), and { ok: true, grantId } for usage.grant."
          }
        }
      }
    },
    "cancel.confirmed": {
      "post": {
        "summary": "The customer confirmed the cancellation: cancel (fulfilment).",
        "description": "The customer confirmed the cancellation: cancel (fulfilment). Signed with x-tenure-signature over \"<x-tenure-timestamp>.<raw body>\".",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received. Answer { ok, reference } for fulfilment events (cancel.confirmed, entitlement.grant), and { ok: true, grantId } for usage.grant."
          }
        }
      }
    },
    "session.escalated": {
      "post": {
        "summary": "The session was handed to a human.",
        "description": "The session was handed to a human. Signed with x-tenure-signature over \"<x-tenure-timestamp>.<raw body>\".",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received. Answer { ok, reference } for fulfilment events (cancel.confirmed, entitlement.grant), and { ok: true, grantId } for usage.grant."
          }
        }
      }
    },
    "subscription.resumed": {
      "post": {
        "summary": "A paused subscription was resumed from the pause wall.",
        "description": "A paused subscription was resumed from the pause wall. Signed with x-tenure-signature over \"<x-tenure-timestamp>.<raw body>\".",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received. Answer { ok, reference } for fulfilment events (cancel.confirmed, entitlement.grant), and { ok: true, grantId } for usage.grant."
          }
        }
      }
    },
    "refund.completed": {
      "post": {
        "summary": "A refund was issued through Tenure (POST /sessions/{id}/refund, /transactions/{id}/refund, or a REBATE accepted in a refund flow). Informational: carries `refund` (the Refund block) and, on a session, the session and customer blocks.",
        "description": "A refund was issued through Tenure (POST /sessions/{id}/refund, /transactions/{id}/refund, or a REBATE accepted in a refund flow). Informational: carries `refund` (the Refund block) and, on a session, the session and customer blocks. Signed with x-tenure-signature over \"<x-tenure-timestamp>.<raw body>\".",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received. Answer { ok, reference } for fulfilment events (cancel.confirmed, entitlement.grant), and { ok: true, grantId } for usage.grant."
          }
        }
      }
    },
    "test.ping": {
      "post": {
        "summary": "The Send test button on Integrations.",
        "description": "The Send test button on Integrations. Signed with x-tenure-signature over \"<x-tenure-timestamp>.<raw body>\".",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received. Answer { ok, reference } for fulfilment events (cancel.confirmed, entitlement.grant), and { ok: true, grantId } for usage.grant."
          }
        }
      }
    }
  },
  "x-mcp": {
    "endpoint": "https://app.trytenure.co/api/mcp",
    "profiles": {
      "agent": "https://app.trytenure.co/api/mcp?profile=agent",
      "admin": "https://app.trytenure.co/api/mcp"
    },
    "resourceMetadata": "https://app.trytenure.co/.well-known/oauth-protected-resource"
  }
}