{
  "openapi": "3.1.0",
  "info": {
    "title": "GTM Swag API",
    "version": "1.0.0",
    "summary": "Personalized, thoughtful gifts that help GTM teams get meetings. Agents prepare; people approve.",
    "description": "GTM Swag sends personalized physical gifts for GTM teams. Agents prepare and track; people approve and pay.\n\n## Quickstart\n1. **Authenticate** with a workspace key from Settings → Integrations: `Authorization: Bearer gtm_<64 hex>`. Base URL `https://gtmswag.com/api/v1`. A key acts as the member who created it, in one workspace. MCP OAuth access tokens (`mco_access_…`) work only on the gift-link distribution routes; over OAuth use MCP at https://gtmswag.com/mcp.\n2. **Read** `GET /workflow`: the workspace mode, what this key may do, and the recovery rule for each error code.\n3. **Choose a gift** with `GET /catalog` (public): a product with `retired:false` and `available` not false.\n4. **Create a playbook**: `POST /campaigns` with `mode:\"always_on\"`, `status:\"draft\"`, no recipients and an `idempotencyKey`. A signed-in person turns it on at `https://gtmswag.com/campaigns/{id}?review=1`.\n5. **Add people** once per trigger: `POST /playbooks/{id}/people`, then read `approval.state`: `auto_approved` (paid from the balance under the playbook's auto-approve rule), `waiting` with a `reason`, `scheduled`, `approved` or `skipped`.\n6. **Hand off**: `GET /queue` lists who waits, each with an `approvalUrl`; `GET /balance` returns `topUpUrl` when `lowBalance` is true. Agents never approve, skip, pay or top up.\n7. **Track**: poll `GET /events` with the last `nextCursor`, or have a person add a webhook (see `webhooks`).\n\n## Responses and errors\nSuccess bodies are `{\"data\": …}` (CSV and file downloads excepted). Every error uses one envelope, `{error, code, nextAction, url?, retryable, retryAfterMs?}`; follow `nextAction`: `open_url` (hand `url` to a person), `reread_and_retry` (state changed: re-read, then retry), `ask_user` (fix the input), `retry_later` (wait `retryAfterMs`), `stop`. Operations tagged **Human only** (`x-human-only: true`, `x-agent-callable: false`) are done by a signed-in person in the browser; keys receive 403 `HUMAN_APPROVAL_REQUIRED` with the `url` to hand over.\n\n## Writes\nA POST, PATCH or DELETE with a body needs `Content-Type: application/json` (the raw artwork upload excepted) and at most 1 MiB. An operation without a `requestBody` reads none: send no body, and with a workspace key no Content-Type. A browser `Origin` header must be https://gtmswag.com.\n\n## Schemas\nEvery JSON success body is a named envelope around a named payload: `CampaignResponse` is `{\"data\": Campaign}`, `CampaignListResponse` is `{\"data\": [Campaign]}`. Unions carry a `discriminator` where a property names the variant: `approval.state` (`PlaybookApproval`), photo `action` (`RecipientPhotoChange`) and `source` (`RecipientPhoto`), and event `type` (`GiftEvent`). The other unions have no such property: nullable values (`anyOf` with `null`), `UrlOrEmpty` and `EmailOrEmpty` strings, and \"send exactly one of\" rules. For tools that read only OpenAPI 3.0, the same API is described in 3.0.3 at https://gtmswag.com/openapi-3.0.json (webhooks under `x-webhooks`).\n\n## Idempotency and versions\n`POST /campaigns` takes an `idempotencyKey`: the same key and body return the same campaign; a different body returns 409 `IDEMPOTENCY_CONFLICT`. `POST /playbooks/{id}/people` is idempotent on `recipient.sourceSystem` + `recipient.externalId`. `POST /sends/{id}/outcomes` deduplicates on `source` + `externalEventId`. Edits carry versions (`expectedPolicyVersion`, a link's `generation` and `expectedMessageVersion`); a stale one returns 409: re-read and retry. After a timeout, re-read before retrying a write.\n\n## Rate limits\n240 requests a minute per workspace, shared by REST and MCP; artwork routes have their own 1,200 reads and 600 writes a minute. Over the limit: 429 `RATE_LIMIT` with `retryAfterMs` (the rest of the minute) in the body and a `Retry-After` header in whole seconds. `GET /catalog` and `GET /session` are not rate limited.\n\n## Test and live\nEvery workspace starts in `test` mode until live gifting is enabled for it. Each gift keeps its mode (`testMode`, `mode`), and test balance never pays for live gifts.",
    "contact": {
      "name": "GTM Swag support",
      "url": "https://gtmswag.com/support"
    },
    "termsOfService": "https://gtmswag.com/terms"
  },
  "externalDocs": {
    "description": "Agent gifting guide",
    "url": "https://gtmswag.com/agent-guide.md"
  },
  "servers": [
    {
      "url": "https://gtmswag.com/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Workflow",
      "description": "Start here: what this key can do in this workspace, the playbook-first steps and how to recover from each error code."
    },
    {
      "name": "Catalog",
      "description": "Choose a gift. Public; no key needed. Use only non-retired, available products."
    },
    {
      "name": "Playbooks",
      "description": "Always-on gifting, one person per trigger (new role, signup, closed deal). Add people and read `approval.state`; a signed-in owner or admin may set an auto-approve rule with a per-gift limit and a monthly budget."
    },
    {
      "name": "Campaigns",
      "description": "Create and edit playbooks (`mode:\"always_on\"`) and fixed-list batch campaigns, manage rosters, preview totals and blockers. Drafts are reviewed and turned on by a person."
    },
    {
      "name": "Queue & balance",
      "description": "Who waits for approval (hand each `approvalUrl` to a person) and whether the balance covers them (hand `topUpUrl` over when `lowBalance`). Approving, skipping and topping up are human only."
    },
    {
      "name": "Gifts",
      "description": "Individual gifts (sends): list, read, review recipient photos, quote batch gifts and draft notes."
    },
    {
      "name": "Gift links",
      "description": "Private claim links for gifts whose recipients confirm their own address: status, copyable links and CSV exports for the customer's own outreach, welcome messages, revoke and regift. Distribution routes also accept MCP OAuth tokens."
    },
    {
      "name": "Tracking & events",
      "description": "Gift status snapshots, the append-only event feed (`send.link_opened`, `send.auto_approved`…), customer-reported outcomes, campaign results and reports."
    },
    {
      "name": "Webhooks",
      "description": "Signed HTTPS callbacks for gift and playbook events. Owners and admins create endpoints in the browser; keys can list endpoints, read deliveries and retry dead ones. Payloads are under `webhooks`. Each delivery is a `POST` with `Content-Type: application/json` and two headers: `X-GTM-Swag-Event-Id` (the event `id`, the same on every attempt) and `X-GTM-Swag-Signature: t=<unix seconds>,v1=<hex>`. To verify, compute HMAC-SHA256 over `<t>.<raw request body>` with the endpoint's `secret` as the key (the 64-character string returned when the endpoint was created, used as UTF-8 text, not hex-decoded), hex-encode it in lowercase, and compare it with `v1` in constant time. Reject old `t` values (a few minutes) and deduplicate on the event ID: delivery is at least once. Answer 2xx within 10 seconds; redirects are not followed and count as failures. A failed delivery is retried after 1, 2, 4, 8, 16, 32 and 64 minutes, then marked `dead` (retry it with `POST /webhooks/{id}/deliveries/{deliveryId}/retry`). Deliveries come from a background job, so allow a few minutes. Test and live events reach the same endpoints: check `mode`. Only events created after the endpoint exists are sent; there is no test or ping event."
    },
    {
      "name": "Artwork",
      "description": "Upload logos, artwork and recipient portraits, or import a photo from a public URL, for use in campaigns and gifts."
    },
    {
      "name": "Billing",
      "description": "Checkout for batch campaigns and reviewed live gifts. Reading is open to owner and admin keys; paying, cancelling and refunds are human only."
    },
    {
      "name": "Team & settings",
      "description": "Workspace defaults (sender, brand), team members and invitations."
    },
    {
      "name": "Human only",
      "description": "A signed-in person does these in the browser at gtmswag.com (most need an owner or admin). API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url`: hand it to that person. They are listed so agents know they exist and what to hand over; each carries `x-human-only: true` and `x-agent-callable: false`."
    }
  ],
  "paths": {
    "/workflow": {
      "get": {
        "operationId": "getWorkflowGuide",
        "tags": ["Workflow"],
        "summary": "Read the playbook-first workflow guide",
        "description": "Start here. Returns the connected workspace's mode (`test` or `live`), what this key may do (`capabilities`), the playbook-first and batch steps, what each `approval.reason` means, limits, and a recovery rule per error code. Same as MCP `get_workflow_guide`.",
        "x-mcp-tool": "get_workflow_guide",
        "x-agent-callable": true,
        "responses": {
          "200": {
            "description": "Success: `{\"data\": WorkflowGuide}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowGuideResponse"
                },
                "examples": {
                  "guide": {
                    "summary": "A workspace key in a test workspace (prose abridged with …)",
                    "value": {
                      "data": {
                        "mode": "test",
                        "connectorCanSend": false,
                        "approvalRequired": true,
                        "capabilities": {
                          "prepareCampaigns": true,
                          "manageExistingInvitations": true,
                          "manageWorkspaceWithinRole": true,
                          "changeTeamMembersOrWebhooks": false,
                          "purchaseOrAuthorizeNewSends": false,
                          "prospectEmailAvailable": false,
                          "privateLinks": true
                        },
                        "instructions": "GTM Swag sends personalized physical gifts for B2B go-to-market teams in the US. You prepare gifts; an owner or admin on the team approves the spend. …",
                        "apiBase": "https://gtmswag.com/api/v1",
                        "mcpEndpoint": "https://gtmswag.com/mcp",
                        "reviewUrlTemplate": "https://gtmswag.com/campaigns/{campaignId}?review=1",
                        "documentation": {
                          "guide": "https://gtmswag.com/agent-guide.md",
                          "api": "https://gtmswag.com/api-docs",
                          "apiMarkdown": "https://gtmswag.com/api-docs.md",
                          "connection": "https://gtmswag.com/guides/connect",
                          "chatgpt": "https://gtmswag.com/guides/chatgpt.md"
                        },
                        "status": "This workspace has mode \"test\": everything works end to end, but no gift is produced or shipped and no real money moves. …",
                        "usageOrder": "Playbooks first (always-on, one person per trigger), then batches for a fixed list, then single gifts.",
                        "steps": [
                          "Pick a gift: search_gifts with the goal's useCase and a per-person budgetCents, then get_gift for the chosen gift's requirements. …",
                          "Reuse a playbook from list_campaigns with mode always_on, or create_campaign with mode:\"always_on\", status draft and a stable idempotencyKey. …"
                        ],
                        "batchSteps": [
                          "For a fixed list, read the catalog and select a gift with retired false and available true. …"
                        ],
                        "approvalReasons": {
                          "auto_approve_off": "The playbook has no auto-approve rule. Hand approvalUrl to an owner or admin. …",
                          "low_balance": "The balance cannot cover the gift. Hand topUpUrl from get_balance to an owner or admin. …"
                        },
                        "tracking": "Watch for send.link_opened with list_tracking_events: it means a recipient opened their private gift link. …",
                        "limits": {
                          "recipientsPerCampaign": 500,
                          "recipientsPerPlaybook": 2000,
                          "giftMessageCharacters": 500,
                          "requestBytes": 1048576,
                          "requestsPerWorkspacePerMinute": 240,
                          "giftLinkExpiryDays": 14,
                          "sourceUploadPartBytes": 150000,
                          "sourceUploadParts": 384,
                          "sourceUploadSerializedBytes": 33554432,
                          "sourceUploadExpiryHours": 6
                        },
                        "recovery": {
                          "LIVE_ADDRESSLESS_UNAVAILABLE": "Add a sender-supplied US address with addressMode known, or stop and report the blocker. …",
                          "CAPABILITY_RETIRED": "Return an eligible private link or CSV for the customer's own outreach. …",
                          "UPLOAD_CAPACITY": "Finish existing uploads or wait for their six-hour expiry. …",
                          "INSUFFICIENT_BALANCE": "Hand topUpUrl to an owner or admin; retry after they add funds. …",
                          "BUDGET_CAP": "Hand the returned url to an owner or admin to raise monthlyBudgetCents. …",
                          "PLAYBOOK_OFF": "Hand the review url to a teammate to turn the playbook on, then retry. …",
                          "PLAYBOOK_BUSY": "Wait retryAfterMs and send the same call again. …",
                          "NOT_ALWAYS_ON": "Use add_recipients for a batch or single campaign. …",
                          "APPROVAL_REQUIRED": "Hand the person's approvalUrl to an owner or admin. …",
                          "MODE_LOCKED": "Create a new playbook instead of changing this campaign. …",
                          "RECIPIENT_SKIPPED": "Do not re-add them; a person can undo the skip. …",
                          "INSUFFICIENT_SCOPE": "Ask the user to reconnect with the needed permission. …",
                          "AUTH_REQUIRED": "Ask the user to reconnect and start a new session. …"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/session": {
      "get": {
        "operationId": "getSession",
        "tags": ["Workflow"],
        "summary": "Read who the key acts as",
        "description": "Returns the member a workspace key belongs to (`teamId`, `teamRole`, `workspaceMode`), or `null` without credentials. Owner and admin keys can do the few owner-or-admin actions open to keys, such as editing workspace settings. Not rate limited.",
        "x-agent-callable": true,
        "security": [
          {},
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Session | null}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionResponse"
                },
                "examples": {
                  "key": {
                    "summary": "The member a workspace key belongs to",
                    "value": {
                      "data": {
                        "id": "usr_2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b",
                        "teamId": "team_7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a",
                        "teamRole": "admin",
                        "name": "Alex Kim",
                        "email": "alex@acme.example",
                        "company": "Acme",
                        "emailVerified": true,
                        "isAdmin": false,
                        "isDemo": false,
                        "liveEnabled": false,
                        "workspaceMode": "test"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated: `AUTH_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "INVALID_KEY": {
                    "$ref": "#/components/examples/INVALID_KEY"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/catalog": {
      "get": {
        "operationId": "listCatalog",
        "tags": ["Catalog"],
        "summary": "List gifts with prices and requirements",
        "description": "Public, no key needed, not rate limited. Includes retired products for history; choose only `retired:false` with `available` not false for new campaigns. Prices are USD cents; `shippingQuoteRequired` means delivery is quoted separately. MCP `search_gifts` ranks gifts for a goal and budget.",
        "x-agent-callable": true,
        "security": [],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [CatalogProduct]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogProductListResponse"
                },
                "examples": {
                  "one": {
                    "summary": "One current product (the live list holds every product)",
                    "value": {
                      "data": [
                        {
                          "id": "gtm-personalized-team-candle-v1",
                          "name": "Personalized Team Candle · 7 oz",
                          "tagline": "A thank-you that stays on the desk.",
                          "description": "A seven-ounce coconut-wax-blend candle in a clear glass jar with a “best team” label and your name or company signature. Choose a scent for a team thank-you or a milestone celebration.",
                          "category": "Something personal",
                          "priceCents": 3300,
                          "shippingCents": 0,
                          "leadDays": "Allow roughly 6–10 business days after approval",
                          "color": "#f6f5f0",
                          "image": "/images/catalog/gtm-personalized-team-candle-gtm-example-v2.webp",
                          "personalization": [
                            "Label signature line",
                            "Scent choice"
                          ],
                          "occasion": "Something personal",
                          "message": "{{firstName}}, a small thank-you for the people behind the {{company}} launch. Hope the team gets a moment to enjoy it.",
                          "verified": false,
                          "featured": false,
                          "requiresArtwork": false,
                          "requiresPortrait": false,
                          "fulfillmentKind": "standard",
                          "deliveryNote": "Standard seven-ounce jar, not the mini sample. Follow the supplied candle-care and burn instructions.",
                          "retired": false,
                          "catalogStatus": "sourced",
                          "giftType": "desk",
                          "shippingQuoteRequired": false,
                          "priceQuoteRequired": false,
                          "quoteDetails": {
                            "configuration": "One 7 oz jar; White Tea scent.",
                            "decoration": "Personalized name or company signature on the printed label; standard “best team” design.",
                            "inputs": [
                              "Exact signature line for the label",
                              "Preferred scent and number of candles with each signature"
                            ],
                            "proof": "Confirm the final size before production."
                          },
                          "imageLabel": "Illustrative personalization",
                          "example": {
                            "occasion": "Thank a launch team",
                            "artwork": "The standard “best team” label signed “GTM Swag launch crew.”"
                          },
                          "estimateIncludesDelivery": true,
                          "fixedPrice": true
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns": {
      "get": {
        "operationId": "listCampaigns",
        "tags": ["Campaigns"],
        "summary": "List campaigns and playbooks",
        "description": "Newest first, every campaign in the workspace with its roster, limits, `policyVersion` and, for a playbook, its `autoApprove` rule. Filter with `mode=always_on` to find playbooks to reuse. Not paginated.",
        "x-mcp-tool": "list_campaigns",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "Only this kind: always_on playbooks, batch lists or single gifts.",
            "schema": {
              "type": "string",
              "enum": ["always_on", "batch", "single"]
            },
            "example": "always_on"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [Campaign]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignListResponse"
                },
                "examples": {
                  "playbooks": {
                    "summary": "mode=always_on: one active playbook with auto-approve on",
                    "value": {
                      "data": [
                        {
                          "id": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "name": "New VP of Sales welcome",
                          "description": "",
                          "mode": "always_on",
                          "status": "active",
                          "productId": "gtm-personalized-team-candle-v1",
                          "budgetCents": 100000000,
                          "perPersonCents": 3300,
                          "maxSends": 2000,
                          "spentCents": 0,
                          "sentCount": 0,
                          "monthlyBudgetCents": 50000,
                          "senderName": "Alex Kim",
                          "senderCompany": "Acme",
                          "message": "Congrats on the new role, {{firstName}}. Here's to what you build next.",
                          "meetingUrl": "",
                          "recipientSource": "workflow",
                          "recipients": [],
                          "policyVersion": 2,
                          "requiresPayment": false,
                          "createdAt": "2026-10-11T15:04:05.000Z",
                          "autoApprove": {
                            "enabled": true,
                            "perGiftMaxCents": 5000,
                            "enabledBy": "usr_2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b",
                            "enabledAt": "2026-10-11T15:04:05.000Z"
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_listCampaigns"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createCampaign",
        "tags": ["Campaigns"],
        "summary": "Create a playbook or campaign draft",
        "description": "Prefer `mode:\"always_on\"` (a playbook) with no recipients: limits default from the gift (`budgetCents` 100,000,000, `perPersonCents` the gift and shipping, `maxSends` 2,000). Batch and single campaigns also need `budgetCents`, `perPersonCents` and `maxSends` (at most 500 people). Saves a draft; a signed-in person turns it on at `https://gtmswag.com/campaigns/{id}?review=1`. Keys cannot set `status:\"active\"` (403 HUMAN_APPROVAL_REQUIRED) or `autoApprove`. Idempotent with `idempotencyKey`: the same key and body return the same campaign (201); the same key with a different body returns 409 IDEMPOTENCY_CONFLICT.",
        "x-mcp-tool": "create_campaign",
        "x-agent-callable": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipientSource": {
                    "type": "string",
                    "enum": ["manual", "workflow"],
                    "description": "Manual roster or external workflow."
                  },
                  "mode": {
                    "default": "batch",
                    "type": "string",
                    "enum": ["always_on", "batch", "single"],
                    "description": "always_on keeps sending; batch is one roster; single is one gift."
                  },
                  "monthlyBudgetCents": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 100000000,
                    "description": "Monthly spend limit in USD cents for always-on campaigns."
                  },
                  "customization": {
                    "$ref": "#/components/schemas/Customization"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Campaign name for review and lookup."
                  },
                  "description": {
                    "default": "",
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Internal campaign description."
                  },
                  "attribution": {
                    "$ref": "#/components/schemas/Attribution"
                  },
                  "productId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Current catalog gift ID; never invented."
                  },
                  "status": {
                    "default": "draft",
                    "type": "string",
                    "enum": ["draft", "active", "paused", "completed"],
                    "description": "Campaign state; connectors prepare drafts."
                  },
                  "budgetCents": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100000000,
                    "description": "Campaign limit in USD cents."
                  },
                  "perPersonCents": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000000,
                    "description": "Per-person USD cents, within budget."
                  },
                  "maxSends": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2000,
                    "description": "Maximum campaign recipient count."
                  },
                  "senderName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Gift sender's name."
                  },
                  "senderCompany": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Gift sender's company."
                  },
                  "message": {
                    "default": "",
                    "type": "string",
                    "maxLength": 500,
                    "description": "Printed note and recipient fallback."
                  },
                  "meetingUrl": {
                    "$ref": "#/components/schemas/UrlOrEmpty",
                    "description": "Optional meeting URL; empty string clears it."
                  },
                  "recipients": {
                    "maxItems": 2000,
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/RecipientInput"
                    },
                    "description": "Distinct recipient identities; email and company are optional."
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 150,
                    "description": "Same key for identical retries only."
                  }
                },
                "required": [
                  "name",
                  "productId",
                  "senderName",
                  "senderCompany"
                ],
                "additionalProperties": false
              },
              "examples": {
                "playbook": {
                  "summary": "Always-on playbook draft (preferred)",
                  "value": {
                    "name": "New VP of Sales welcome",
                    "productId": "gtm-personalized-team-candle-v1",
                    "mode": "always_on",
                    "status": "draft",
                    "monthlyBudgetCents": 50000,
                    "senderName": "Alex Kim",
                    "senderCompany": "Acme",
                    "message": "Congrats on the new role, {{firstName}}. Here's to what you build next.",
                    "idempotencyKey": "new-vp-playbook-2026"
                  }
                },
                "batch": {
                  "summary": "Batch campaign draft for a fixed list",
                  "value": {
                    "name": "Q4 champions thank-you",
                    "productId": "gtm-personalized-team-candle-v1",
                    "mode": "batch",
                    "status": "draft",
                    "budgetCents": 50000,
                    "perPersonCents": 5000,
                    "maxSends": 10,
                    "senderName": "Alex Kim",
                    "senderCompany": "Acme",
                    "message": "Thank you for championing us this year, {{firstName}}.",
                    "idempotencyKey": "q4-champions-2026",
                    "recipients": [
                      {
                        "name": "Priya Patel",
                        "email": "priya@lumen.example",
                        "company": "Lumen",
                        "sourceSystem": "salesforce",
                        "externalId": "003Hs00001XyZ",
                        "address": "500 Congress Ave",
                        "city": "Austin",
                        "state": "TX",
                        "zip": "78701",
                        "country": "US",
                        "addressMode": "known"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success: `{\"data\": Campaign}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResponse"
                },
                "examples": {
                  "playbook": {
                    "summary": "The saved playbook draft",
                    "value": {
                      "data": {
                        "id": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "name": "New VP of Sales welcome",
                        "description": "",
                        "mode": "always_on",
                        "status": "draft",
                        "productId": "gtm-personalized-team-candle-v1",
                        "budgetCents": 100000000,
                        "perPersonCents": 3300,
                        "maxSends": 2000,
                        "spentCents": 0,
                        "sentCount": 0,
                        "monthlyBudgetCents": 50000,
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "message": "Congrats on the new role, {{firstName}}. Here's to what you build next.",
                        "meetingUrl": "",
                        "recipientSource": "workflow",
                        "recipients": [],
                        "policyVersion": 1,
                        "requiresPayment": false,
                        "createdAt": "2026-10-11T15:04:05.000Z"
                      }
                    }
                  },
                  "batch": {
                    "summary": "The saved batch draft",
                    "value": {
                      "data": {
                        "id": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                        "name": "Q4 champions thank-you",
                        "description": "",
                        "mode": "batch",
                        "status": "draft",
                        "productId": "gtm-personalized-team-candle-v1",
                        "budgetCents": 50000,
                        "perPersonCents": 5000,
                        "maxSends": 10,
                        "spentCents": 0,
                        "sentCount": 0,
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "message": "Thank you for championing us this year, {{firstName}}.",
                        "meetingUrl": "",
                        "recipientSource": "workflow",
                        "recipients": [
                          {
                            "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                            "name": "Priya Patel",
                            "email": "priya@lumen.example",
                            "company": "Lumen",
                            "sourceSystem": "salesforce",
                            "externalId": "003Hs00001XyZ",
                            "address": "500 Congress Ave",
                            "city": "Austin",
                            "state": "TX",
                            "zip": "78701",
                            "country": "US",
                            "addressMode": "known"
                          }
                        ],
                        "policyVersion": 1,
                        "requiresPayment": false,
                        "createdAt": "2026-10-11T15:04:05.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `INVALID_REQUEST`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "TOO_MANY_ARTWORK_FILES": {
                    "$ref": "#/components/examples/TOO_MANY_ARTWORK_FILES"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `ARTWORK_UNAVAILABLE`, `RECIPIENT_SCOPE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
                  },
                  "ARTWORK_UNAVAILABLE": {
                    "$ref": "#/components/examples/ARTWORK_UNAVAILABLE"
                  },
                  "RECIPIENT_SCOPE": {
                    "$ref": "#/components/examples/RECIPIENT_SCOPE"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict: `IDEMPOTENCY_CONFLICT`, `GIFT_RETIRED`, `GIFT_UNAVAILABLE`, `PRICE_QUOTE_REQUIRED`, `RECIPIENT_IDENTITY_CONFLICT`, `DUPLICATE_RECIPIENT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "IDEMPOTENCY_CONFLICT": {
                    "$ref": "#/components/examples/IDEMPOTENCY_CONFLICT"
                  },
                  "GIFT_RETIRED": {
                    "$ref": "#/components/examples/GIFT_RETIRED"
                  },
                  "GIFT_UNAVAILABLE": {
                    "$ref": "#/components/examples/GIFT_UNAVAILABLE"
                  },
                  "PRICE_QUOTE_REQUIRED": {
                    "$ref": "#/components/examples/PRICE_QUOTE_REQUIRED"
                  },
                  "RECIPIENT_IDENTITY_CONFLICT": {
                    "$ref": "#/components/examples/RECIPIENT_IDENTITY_CONFLICT"
                  },
                  "DUPLICATE_RECIPIENT": {
                    "$ref": "#/components/examples/DUPLICATE_RECIPIENT"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}": {
      "get": {
        "operationId": "getCampaign",
        "tags": ["Campaigns"],
        "summary": "Read a campaign",
        "description": "Current settings, roster (with stable `recipientId`s), `policyVersion` and, for a playbook, the read-only `autoApprove` rule. Read it before any edit: edits need the current `policyVersion`.",
        "x-mcp-tool": "get_campaign",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Campaign}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResponse"
                },
                "examples": {
                  "playbook": {
                    "summary": "An active playbook with auto-approve on",
                    "value": {
                      "data": {
                        "id": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "name": "New VP of Sales welcome",
                        "description": "",
                        "mode": "always_on",
                        "status": "active",
                        "productId": "gtm-personalized-team-candle-v1",
                        "budgetCents": 100000000,
                        "perPersonCents": 3300,
                        "maxSends": 2000,
                        "spentCents": 0,
                        "sentCount": 0,
                        "monthlyBudgetCents": 50000,
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "message": "Congrats on the new role, {{firstName}}. Here's to what you build next.",
                        "meetingUrl": "",
                        "recipientSource": "workflow",
                        "recipients": [],
                        "policyVersion": 2,
                        "requiresPayment": false,
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "autoApprove": {
                          "enabled": true,
                          "perGiftMaxCents": 5000,
                          "enabledBy": "usr_2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b",
                          "enabledAt": "2026-10-11T15:04:05.000Z"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "operationId": "updateCampaign",
        "tags": ["Campaigns"],
        "summary": "Edit a campaign",
        "description": "Only supplied fields change. API keys must send the current `expectedPolicyVersion` (a stale one returns 409 POLICY_CHANGED). A key edit returns the campaign to draft for review (unless it is paused or completed); keys cannot set `status:\"active\"`. While a playbook's auto-approve is on, raising `monthlyBudgetCents` needs a signed-in owner or admin. One exception: a body with only `recipients` that keeps every current person and appends new ones adds them to an active playbook without a version and keeps it on, like `POST /playbooks/{id}/people`.",
        "x-mcp-tool": "update_campaign",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipientSource": {
                    "type": "string",
                    "enum": ["manual", "workflow"],
                    "description": "Manual roster or external workflow."
                  },
                  "mode": {
                    "default": "batch",
                    "type": "string",
                    "enum": ["always_on", "batch", "single"],
                    "description": "always_on keeps sending; batch is one roster; single is one gift."
                  },
                  "monthlyBudgetCents": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 100000000,
                    "description": "Monthly spend limit in USD cents for always-on campaigns."
                  },
                  "customization": {
                    "$ref": "#/components/schemas/Customization"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Campaign name for review and lookup."
                  },
                  "description": {
                    "default": "",
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Internal campaign description."
                  },
                  "attribution": {
                    "$ref": "#/components/schemas/Attribution"
                  },
                  "productId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Current catalog gift ID; never invented."
                  },
                  "status": {
                    "default": "draft",
                    "type": "string",
                    "enum": ["draft", "active", "paused", "completed"],
                    "description": "Campaign state; connectors prepare drafts."
                  },
                  "budgetCents": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100000000,
                    "description": "Campaign limit in USD cents."
                  },
                  "perPersonCents": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000000,
                    "description": "Per-person USD cents, within budget."
                  },
                  "maxSends": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2000,
                    "description": "Maximum campaign recipient count."
                  },
                  "senderName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Gift sender's name."
                  },
                  "senderCompany": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Gift sender's company."
                  },
                  "message": {
                    "default": "",
                    "type": "string",
                    "maxLength": 500,
                    "description": "Printed note and recipient fallback."
                  },
                  "meetingUrl": {
                    "$ref": "#/components/schemas/UrlOrEmpty",
                    "description": "Optional meeting URL; empty string clears it."
                  },
                  "recipients": {
                    "maxItems": 2000,
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/RecipientInput"
                    },
                    "description": "Distinct recipient identities; email and company are optional."
                  },
                  "expectedPolicyVersion": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The campaign's current policyVersion; a stale value returns POLICY_CHANGED."
                  }
                },
                "additionalProperties": false
              },
              "examples": {
                "note": {
                  "summary": "Change the note and monthly budget",
                  "value": {
                    "expectedPolicyVersion": 2,
                    "message": "Welcome aboard, {{firstName}}. Rooting for your first quarter.",
                    "monthlyBudgetCents": 40000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Campaign}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResponse"
                },
                "examples": {
                  "draft": {
                    "summary": "The edit put the playbook back in draft for review",
                    "value": {
                      "data": {
                        "id": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "name": "New VP of Sales welcome",
                        "description": "",
                        "mode": "always_on",
                        "status": "draft",
                        "productId": "gtm-personalized-team-candle-v1",
                        "budgetCents": 100000000,
                        "perPersonCents": 3300,
                        "maxSends": 2000,
                        "spentCents": 0,
                        "sentCount": 0,
                        "monthlyBudgetCents": 40000,
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "message": "Welcome aboard, {{firstName}}. Rooting for your first quarter.",
                        "meetingUrl": "",
                        "recipientSource": "workflow",
                        "recipients": [],
                        "policyVersion": 3,
                        "requiresPayment": false,
                        "createdAt": "2026-10-11T15:04:05.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`, `ARTWORK_UNAVAILABLE`, `RECIPIENT_SCOPE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED"
                  },
                  "TEAM_MANAGER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
                  },
                  "ARTWORK_UNAVAILABLE": {
                    "$ref": "#/components/examples/ARTWORK_UNAVAILABLE"
                  },
                  "RECIPIENT_SCOPE": {
                    "$ref": "#/components/examples/RECIPIENT_SCOPE"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `CHECKOUT_LOCKED`, `POLICY_CHANGED`, `MODE_LOCKED`, `INVALID_REQUEST`, `GIFT_RETIRED`, `GIFT_UNAVAILABLE`, `PRICE_QUOTE_REQUIRED`, `RECIPIENT_IDENTITY_CONFLICT`, `DUPLICATE_RECIPIENT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "CHECKOUT_LOCKED": {
                    "$ref": "#/components/examples/CHECKOUT_LOCKED"
                  },
                  "POLICY_CHANGED": {
                    "$ref": "#/components/examples/POLICY_CHANGED"
                  },
                  "MODE_LOCKED": {
                    "$ref": "#/components/examples/MODE_LOCKED"
                  },
                  "LIMITS_BELOW_COMMITMENTS": {
                    "$ref": "#/components/examples/LIMITS_BELOW_COMMITMENTS"
                  },
                  "GIFT_RETIRED": {
                    "$ref": "#/components/examples/GIFT_RETIRED"
                  },
                  "GIFT_UNAVAILABLE": {
                    "$ref": "#/components/examples/GIFT_UNAVAILABLE"
                  },
                  "PRICE_QUOTE_REQUIRED": {
                    "$ref": "#/components/examples/PRICE_QUOTE_REQUIRED"
                  },
                  "RECIPIENT_IDENTITY_CONFLICT": {
                    "$ref": "#/components/examples/RECIPIENT_IDENTITY_CONFLICT"
                  },
                  "DUPLICATE_RECIPIENT": {
                    "$ref": "#/components/examples/DUPLICATE_RECIPIENT"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/recipients": {
      "post": {
        "operationId": "addRecipients",
        "tags": ["Campaigns"],
        "summary": "Add several people to a campaign",
        "description": "For a batch list or a playbook backfill (up to 500 per call). People already on the roster (same `recipientId`, `sourceSystem`+`externalId`, or one matching email) are skipped. An active playbook needs no `expectedPolicyVersion` and stays on; with auto-approve on, new people are evaluated like single adds. Any other campaign needs the current `expectedPolicyVersion`, returns to draft and its limits expand to fit. For one person per trigger use `POST /playbooks/{id}/people`.",
        "x-mcp-tool": "add_recipients",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipients": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/RecipientInput"
                    },
                    "description": "Distinct recipient identities; email and company are optional."
                  },
                  "expectedPolicyVersion": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The campaign's current policyVersion; a stale value returns POLICY_CHANGED."
                  }
                },
                "required": ["recipients"],
                "additionalProperties": false
              },
              "examples": {
                "batch": {
                  "summary": "Append to a batch draft",
                  "value": {
                    "expectedPolicyVersion": 1,
                    "recipients": [
                      {
                        "name": "Sam Rivera",
                        "email": "sam@orbit.example",
                        "company": "Orbit",
                        "sourceSystem": "salesforce",
                        "externalId": "003Hs00002AbC",
                        "addressMode": "confirm"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Campaign}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResponse"
                },
                "examples": {
                  "batch": {
                    "summary": "The batch draft with the new person",
                    "value": {
                      "data": {
                        "id": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                        "name": "Q4 champions thank-you",
                        "description": "",
                        "mode": "batch",
                        "status": "draft",
                        "productId": "gtm-personalized-team-candle-v1",
                        "budgetCents": 50000,
                        "perPersonCents": 5000,
                        "maxSends": 10,
                        "spentCents": 0,
                        "sentCount": 0,
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "message": "Thank you for championing us this year, {{firstName}}.",
                        "meetingUrl": "",
                        "recipientSource": "workflow",
                        "recipients": [
                          {
                            "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                            "name": "Priya Patel",
                            "email": "priya@lumen.example",
                            "company": "Lumen",
                            "sourceSystem": "salesforce",
                            "externalId": "003Hs00001XyZ",
                            "address": "500 Congress Ave",
                            "city": "Austin",
                            "state": "TX",
                            "zip": "78701",
                            "country": "US",
                            "addressMode": "known"
                          },
                          {
                            "recipientId": "recipient_6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b",
                            "name": "Sam Rivera",
                            "email": "sam@orbit.example",
                            "company": "Orbit",
                            "sourceSystem": "salesforce",
                            "externalId": "003Hs00002AbC",
                            "country": "US",
                            "addressMode": "confirm"
                          }
                        ],
                        "policyVersion": 2,
                        "requiresPayment": false,
                        "createdAt": "2026-10-11T15:04:05.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenArtworkOrRecipientScope"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `POLICY_CHANGED`, `PLAYBOOK_OFF`, `CHECKOUT_LOCKED`, `RECIPIENT_LIMIT`, `PLAYBOOK_BUSY`, `GIFT_RETIRED`, `GIFT_UNAVAILABLE`, `PRICE_QUOTE_REQUIRED`, `RECIPIENT_IDENTITY_CONFLICT`, `DUPLICATE_RECIPIENT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "POLICY_CHANGED": {
                    "$ref": "#/components/examples/POLICY_CHANGED"
                  },
                  "PLAYBOOK_OFF": {
                    "$ref": "#/components/examples/PLAYBOOK_OFF"
                  },
                  "CHECKOUT_LOCKED": {
                    "$ref": "#/components/examples/CHECKOUT_LOCKED"
                  },
                  "RECIPIENT_LIMIT": {
                    "$ref": "#/components/examples/RECIPIENT_LIMIT"
                  },
                  "PLAYBOOK_BUSY": {
                    "$ref": "#/components/examples/PLAYBOOK_BUSY"
                  },
                  "GIFT_RETIRED": {
                    "$ref": "#/components/examples/GIFT_RETIRED"
                  },
                  "GIFT_UNAVAILABLE": {
                    "$ref": "#/components/examples/GIFT_UNAVAILABLE"
                  },
                  "PRICE_QUOTE_REQUIRED": {
                    "$ref": "#/components/examples/PRICE_QUOTE_REQUIRED"
                  },
                  "RECIPIENT_IDENTITY_CONFLICT": {
                    "$ref": "#/components/examples/RECIPIENT_IDENTITY_CONFLICT"
                  },
                  "DUPLICATE_RECIPIENT": {
                    "$ref": "#/components/examples/DUPLICATE_RECIPIENT"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/recipients/bulk": {
      "post": {
        "operationId": "manageRecipients",
        "tags": ["Campaigns"],
        "summary": "Remove unsent people or change their notes",
        "description": "Select people by `recipientIds` (preferred) or by `emails` (each must match exactly one person); send one of the two. `remove` drops them from the roster; `message` replaces their printed note. People who already have a gift cannot be changed (409 RECIPIENT_ALREADY_SENT). Needs the current `expectedPolicyVersion`; the campaign returns to draft for review, an active playbook included.",
        "x-mcp-tool": "manage_recipients",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "expectedPolicyVersion": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The campaign's current policyVersion; a stale value returns POLICY_CHANGED."
                  },
                  "recipientIds": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^recipient_[a-f0-9]{32}$"
                    },
                    "description": "Explicit stable recipient IDs to select."
                  },
                  "emails": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "email",
                      "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                    },
                    "description": "Existing campaign recipient emails to act on."
                  },
                  "action": {
                    "type": "string",
                    "enum": ["remove", "message"],
                    "description": "Remove unsent recipients or edit their printed message."
                  },
                  "message": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Printed note and recipient fallback."
                  }
                },
                "required": ["expectedPolicyVersion", "action"],
                "additionalProperties": false,
                "oneOf": [
                  {
                    "required": ["recipientIds"],
                    "not": {
                      "required": ["emails"]
                    }
                  },
                  {
                    "required": ["emails"],
                    "not": {
                      "required": ["recipientIds"]
                    }
                  }
                ],
                "description": "Send exactly one of `recipientIds` or `emails`."
              },
              "examples": {
                "remove": {
                  "summary": "Remove one unsent person",
                  "value": {
                    "action": "remove",
                    "expectedPolicyVersion": 2,
                    "recipientIds": [
                      "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b"
                    ]
                  }
                },
                "message": {
                  "summary": "Change one person's printed note",
                  "value": {
                    "action": "message",
                    "expectedPolicyVersion": 2,
                    "recipientIds": [
                      "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b"
                    ],
                    "message": "Priya, thank you for a remarkable year together."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Campaign}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResponse"
                },
                "examples": {
                  "removed": {
                    "summary": "The draft without that person",
                    "value": {
                      "data": {
                        "id": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                        "name": "Q4 champions thank-you",
                        "description": "",
                        "mode": "batch",
                        "status": "draft",
                        "productId": "gtm-personalized-team-candle-v1",
                        "budgetCents": 50000,
                        "perPersonCents": 5000,
                        "maxSends": 10,
                        "spentCents": 0,
                        "sentCount": 0,
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "message": "Thank you for championing us this year, {{firstName}}.",
                        "meetingUrl": "",
                        "recipientSource": "workflow",
                        "recipients": [],
                        "policyVersion": 3,
                        "requiresPayment": false,
                        "createdAt": "2026-10-11T15:04:05.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `RECIPIENT_SCOPE`, `MESSAGE_TOO_LONG`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "RECIPIENT_SELECTION": {
                    "$ref": "#/components/examples/RECIPIENT_SELECTION"
                  },
                  "MESSAGE_TOO_LONG": {
                    "$ref": "#/components/examples/MESSAGE_TOO_LONG"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `POLICY_CHANGED`, `CAMPAIGN_COMPLETED`, `RECIPIENT_ALREADY_SENT`, `CHECKOUT_LOCKED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "POLICY_CHANGED": {
                    "$ref": "#/components/examples/POLICY_CHANGED"
                  },
                  "CAMPAIGN_COMPLETED": {
                    "$ref": "#/components/examples/CAMPAIGN_COMPLETED"
                  },
                  "RECIPIENT_ALREADY_SENT": {
                    "$ref": "#/components/examples/RECIPIENT_ALREADY_SENT"
                  },
                  "CHECKOUT_LOCKED": {
                    "$ref": "#/components/examples/CHECKOUT_LOCKED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/preview": {
      "get": {
        "operationId": "previewCampaign",
        "tags": ["Campaigns"],
        "summary": "Preview the total and blockers before review",
        "description": "The exact total for people without a gift yet, `blockers`, `nextAction` (`review` or `provide_sender_address`), `fulfillmentRequirements` and any `prepaidOffer`. Creates nothing and takes no payment.",
        "x-mcp-tool": "preview_campaign",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": CampaignPreview}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignPreviewResponse"
                },
                "examples": {
                  "ready": {
                    "summary": "Ready for review: one person, no blockers",
                    "value": {
                      "data": {
                        "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                        "policyVersion": 1,
                        "recipientCount": 1,
                        "unitCents": 3300,
                        "totalCents": 3300,
                        "currency": "usd",
                        "alreadySent": 0,
                        "nextAction": "review",
                        "unavailableReason": null,
                        "blockers": []
                      }
                    }
                  },
                  "address": {
                    "summary": "Live workspace: unknown addresses need a sender-supplied address",
                    "value": {
                      "data": {
                        "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                        "policyVersion": 1,
                        "recipientCount": 1,
                        "unitCents": 3300,
                        "totalCents": 3300,
                        "currency": "usd",
                        "alreadySent": 0,
                        "nextAction": "provide_sender_address",
                        "unavailableReason": "live_addressless_unavailable",
                        "blockers": [
                          "A shipping address supplied by the sender is required."
                        ],
                        "fulfillmentRequirements": [
                          {
                            "recipientId": "recipient_6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b",
                            "recipientName": "Sam Rivera",
                            "recipientEmail": "sam@orbit.example",
                            "kind": "sender_address_required",
                            "message": "A shipping address supplied by the sender is required."
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/repeats": {
      "get": {
        "operationId": "listCampaignRepeats",
        "tags": ["Campaigns"],
        "summary": "List people already gifted by another campaign",
        "description": "People on this roster who already have a gift from another campaign, with `priorSendId` and whether a person approved the repeat. Auto-approve never approves a repeat (`approval.reason` `repeat_recipient`).",
        "x-mcp-tool": "get_campaign_repeats",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [RepeatRecipient]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RepeatRecipientListResponse"
                },
                "examples": {
                  "repeat": {
                    "summary": "One repeat waiting for a person's approval",
                    "value": {
                      "data": [
                        {
                          "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                          "name": "Jamie Chen",
                          "email": "jamie@northstar.example",
                          "priorSendId": "send_7d9f1b3d5f7a9c1e3b5d7f9a1c3e5a7b",
                          "approved": false
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/repeat-approvals": {
      "post": {
        "operationId": "approveCampaignRepeats",
        "tags": ["Campaigns", "Human only"],
        "summary": "Approve gifts for repeat recipients",
        "description": "Human only: A signed-in teammate does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Hand the campaign review URL to a person; send `recipientIds` (preferred) or `emails` from `GET /campaigns/{id}/repeats`.",
        "x-mcp-tool": "approve_campaign_repeats",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipientIds": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^recipient_[a-f0-9]{32}$"
                    },
                    "description": "Explicit stable recipient IDs to select."
                  },
                  "emails": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "email",
                      "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                    },
                    "description": "Existing campaign recipient emails to act on."
                  }
                },
                "additionalProperties": false,
                "oneOf": [
                  {
                    "required": ["recipientIds"],
                    "not": {
                      "required": ["emails"]
                    }
                  },
                  {
                    "required": ["emails"],
                    "not": {
                      "required": ["recipientIds"]
                    }
                  }
                ],
                "description": "Send exactly one of `recipientIds` or `emails`."
              },
              "examples": {
                "ids": {
                  "summary": "Approve one repeat by ID",
                  "value": {
                    "recipientIds": [
                      "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": OkResult}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResultResponse"
                },
                "examples": {
                  "ok": {
                    "summary": "Approved",
                    "value": {
                      "data": {
                        "ok": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `RECIPIENT_SCOPE`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "REPEAT_SELECTION": {
                    "$ref": "#/components/examples/REPEAT_SELECTION"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnly"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `POLICY_CHANGED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "POLICY_CHANGED": {
                    "$ref": "#/components/examples/POLICY_CHANGED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/launch": {
      "post": {
        "operationId": "launchCampaign",
        "tags": ["Campaigns", "Human only"],
        "summary": "Process approved batch roster positions",
        "description": "Human only: A signed-in teammate does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Processes at most three roster positions per call from `cursor`; `nextCursor` is null once every position is done. A playbook refuses with 409 APPROVAL_REQUIRED (its gifts go through the approval queue). Paid campaigns prepare gifts on their own after payment.",
        "x-mcp-tool": "launch_campaign",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Roster offset to start from: 0, then each nextCursor; null nextCursor means every position was processed.",
            "schema": {
              "default": 0,
              "type": "integer",
              "minimum": 0,
              "maximum": 500
            },
            "example": 3
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": LaunchResult}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LaunchResultResponse"
                },
                "examples": {
                  "done": {
                    "summary": "The last position, processed",
                    "value": {
                      "data": {
                        "sends": [
                          {
                            "id": "send_7d9f1b3d5f7a9c1e3b5d7f9a1c3e5a7b",
                            "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                            "productId": "gtm-personalized-team-candle-v1",
                            "recipient": {
                              "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                              "name": "Priya Patel",
                              "email": "priya@lumen.example",
                              "company": "Lumen",
                              "sourceSystem": "salesforce",
                              "externalId": "003Hs00001XyZ",
                              "address": "500 Congress Ave",
                              "city": "Austin",
                              "state": "TX",
                              "zip": "78701",
                              "country": "US",
                              "addressMode": "known"
                            },
                            "message": "Thank you for championing us this year, Priya.",
                            "senderName": "Alex Kim",
                            "senderCompany": "Acme",
                            "meetingUrl": "",
                            "totalCents": 3300,
                            "status": "queued",
                            "outcome": "none",
                            "createdAt": "2026-10-11T15:04:05.000Z",
                            "testMode": true,
                            "attribution": {},
                            "events": [
                              {
                                "status": "queued",
                                "at": "2026-10-11T15:04:05.000Z",
                                "note": "Gift queued."
                              }
                            ]
                          }
                        ],
                        "errors": [],
                        "nextCursor": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_launchCampaign"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnly"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `APPROVAL_REQUIRED`, `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/APPROVAL_REQUIRED"
                  },
                  "CAMPAIGN_NOT_ACTIVE": {
                    "$ref": "#/components/examples/CAMPAIGN_NOT_ACTIVE"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/playbooks/{id}/people": {
      "post": {
        "operationId": "addToPlaybook",
        "tags": ["Playbooks"],
        "summary": "Add one person to an active playbook",
        "description": "Call once per trigger (new role, signup, closed deal). The playbook stays on; no `policyVersion` needed. Read `approval` in the result:\n\n- `waiting` with a `reason`: the person waits in the approval queue; nothing is charged or sent. Hand `approvalUrl` to a person.\n- `auto_approved` with `sendId`: the playbook's auto-approve rule (set by a signed-in owner or admin) approved the gift within its per-gift limit and monthly budget and paid it from the balance.\n- `scheduled`: the rule finishes it in the background; watch `GET /events` for `send.auto_approved`.\n- `approved` (a person already approved; `sendId`) or `skipped` (a person skipped them).\n\nIdempotent on `recipient.sourceSystem` + `recipient.externalId` (else `recipientId`, then a unique email): a repeat returns `alreadyQueued:true` and never approves or charges twice. A draft or paused playbook refuses with 409 PLAYBOOK_OFF; a batch campaign with 409 NOT_ALWAYS_ON; concurrent adds to one playbook may return 409 PLAYBOOK_BUSY with a short `retryAfterMs` (send the same call again).",
        "x-mcp-tool": "add_to_playbook",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipient": {
                    "$ref": "#/components/schemas/RecipientInput",
                    "description": "Gift recipient, delivery details and personal note."
                  }
                },
                "required": ["recipient"],
                "additionalProperties": false
              },
              "examples": {
                "trigger": {
                  "summary": "One person from a CRM trigger, address unknown",
                  "value": {
                    "recipient": {
                      "name": "Jamie Chen",
                      "email": "jamie@northstar.example",
                      "company": "Northstar",
                      "title": "VP of Sales",
                      "sourceSystem": "hubspot",
                      "externalId": "contact-4821",
                      "addressMode": "confirm"
                    }
                  }
                },
                "knownAddress": {
                  "summary": "With a shipping address the sender supplied",
                  "value": {
                    "recipient": {
                      "name": "Priya Patel",
                      "email": "priya@lumen.example",
                      "company": "Lumen",
                      "sourceSystem": "salesforce",
                      "externalId": "003Hs00001XyZ",
                      "address": "500 Congress Ave",
                      "city": "Austin",
                      "state": "TX",
                      "zip": "78701",
                      "country": "US",
                      "addressMode": "known"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": PlaybookAddResult}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlaybookAddResultResponse"
                },
                "examples": {
                  "waiting": {
                    "summary": "No auto-approve: waits for a person",
                    "value": {
                      "data": {
                        "queued": true,
                        "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                        "alreadyQueued": false,
                        "approvalUrl": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "approval": {
                          "state": "waiting",
                          "reason": "auto_approve_off"
                        }
                      }
                    }
                  },
                  "autoApproved": {
                    "summary": "Auto-approved and paid from the balance",
                    "value": {
                      "data": {
                        "queued": false,
                        "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                        "alreadyQueued": false,
                        "approvalUrl": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "approval": {
                          "state": "auto_approved",
                          "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b"
                        }
                      }
                    }
                  },
                  "overLimit": {
                    "summary": "Auto-approve on, but the gift is over the per-gift limit",
                    "value": {
                      "data": {
                        "queued": true,
                        "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                        "alreadyQueued": false,
                        "approvalUrl": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "approval": {
                          "state": "waiting",
                          "reason": "over_gift_limit"
                        }
                      }
                    }
                  },
                  "scheduled": {
                    "summary": "The rule finishes it in the background",
                    "value": {
                      "data": {
                        "queued": true,
                        "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                        "alreadyQueued": false,
                        "approvalUrl": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "approval": {
                          "state": "scheduled"
                        }
                      }
                    }
                  },
                  "repeat": {
                    "summary": "Same sourceSystem + externalId again: nothing new happens",
                    "value": {
                      "data": {
                        "queued": false,
                        "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                        "alreadyQueued": true,
                        "approvalUrl": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "approval": {
                          "state": "auto_approved",
                          "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenArtworkOrRecipientScope"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `NOT_ALWAYS_ON`, `PLAYBOOK_OFF`, `CHECKOUT_LOCKED`, `RECIPIENT_LIMIT`, `PLAYBOOK_BUSY`, `GIFT_RETIRED`, `GIFT_UNAVAILABLE`, `PRICE_QUOTE_REQUIRED`, `RECIPIENT_IDENTITY_CONFLICT`, `DUPLICATE_RECIPIENT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "NOT_ALWAYS_ON": {
                    "$ref": "#/components/examples/NOT_ALWAYS_ON"
                  },
                  "PLAYBOOK_OFF": {
                    "$ref": "#/components/examples/PLAYBOOK_OFF"
                  },
                  "CHECKOUT_LOCKED": {
                    "$ref": "#/components/examples/CHECKOUT_LOCKED"
                  },
                  "RECIPIENT_LIMIT": {
                    "$ref": "#/components/examples/RECIPIENT_LIMIT"
                  },
                  "PLAYBOOK_BUSY": {
                    "$ref": "#/components/examples/PLAYBOOK_BUSY"
                  },
                  "GIFT_RETIRED": {
                    "$ref": "#/components/examples/GIFT_RETIRED"
                  },
                  "GIFT_UNAVAILABLE": {
                    "$ref": "#/components/examples/GIFT_UNAVAILABLE"
                  },
                  "PRICE_QUOTE_REQUIRED": {
                    "$ref": "#/components/examples/PRICE_QUOTE_REQUIRED"
                  },
                  "RECIPIENT_IDENTITY_CONFLICT": {
                    "$ref": "#/components/examples/RECIPIENT_IDENTITY_CONFLICT"
                  },
                  "DUPLICATE_RECIPIENT": {
                    "$ref": "#/components/examples/DUPLICATE_RECIPIENT"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/auto-approve": {
      "post": {
        "operationId": "setPlaybookAutoApprove",
        "tags": ["Playbooks", "Human only"],
        "summary": "Turn a playbook's auto-approve on or off",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Keys and connections read the rule as `autoApprove` on the campaign. Turning it on, or raising `perGiftMaxCents` or `monthlyBudgetCents`, needs an owner or admin (403 TEAM_MANAGER_REQUIRED), who becomes the person auto-approvals act for; any teammate may lower the limits or turn it off. Turning it on needs a per-gift limit and a monthly budget (400 MONTHLY_BUDGET_REQUIRED) with the limit within the budget. The playbook keeps its status; its `policyVersion` increases.",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean",
                    "description": "true turns auto-approve on; false turns it off."
                  },
                  "perGiftMaxCents": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 100000,
                    "description": "Largest gift (price plus shipping, USD cents) approved without a person, 100 to 100000."
                  },
                  "monthlyBudgetCents": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 100000000,
                    "description": "The playbook's monthly spend limit in USD cents; required to turn auto-approve on."
                  },
                  "expectedPolicyVersion": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The playbook's current policyVersion; a stale value returns POLICY_CHANGED."
                  }
                },
                "required": ["enabled"],
                "additionalProperties": false
              },
              "examples": {
                "on": {
                  "summary": "Turn it on: up to $50 a gift, $500 a month",
                  "value": {
                    "enabled": true,
                    "perGiftMaxCents": 5000,
                    "monthlyBudgetCents": 50000,
                    "expectedPolicyVersion": 2
                  }
                },
                "off": {
                  "summary": "Turn it off",
                  "value": {
                    "enabled": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Campaign}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResponse"
                },
                "examples": {
                  "on": {
                    "summary": "The playbook with its rule",
                    "value": {
                      "data": {
                        "id": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "name": "New VP of Sales welcome",
                        "description": "",
                        "mode": "always_on",
                        "status": "active",
                        "productId": "gtm-personalized-team-candle-v1",
                        "budgetCents": 100000000,
                        "perPersonCents": 3300,
                        "maxSends": 2000,
                        "spentCents": 0,
                        "sentCount": 0,
                        "monthlyBudgetCents": 50000,
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "message": "Congrats on the new role, {{firstName}}. Here's to what you build next.",
                        "meetingUrl": "",
                        "recipientSource": "workflow",
                        "recipients": [],
                        "policyVersion": 3,
                        "requiresPayment": false,
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "autoApprove": {
                          "enabled": true,
                          "perGiftMaxCents": 5000,
                          "enabledBy": "usr_2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b",
                          "enabledAt": "2026-10-11T15:04:05.000Z"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `MONTHLY_BUDGET_REQUIRED`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "MONTHLY_BUDGET_REQUIRED": {
                    "$ref": "#/components/examples/MONTHLY_BUDGET_REQUIRED"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManager"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `NOT_ALWAYS_ON`, `POLICY_CHANGED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "AUTO_APPROVE_NOT_ALWAYS_ON": {
                    "$ref": "#/components/examples/AUTO_APPROVE_NOT_ALWAYS_ON"
                  },
                  "POLICY_CHANGED": {
                    "$ref": "#/components/examples/POLICY_CHANGED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/queue": {
      "get": {
        "operationId": "listQueue",
        "tags": ["Queue & balance"],
        "summary": "List people waiting for approval",
        "description": "Everyone waiting in an active playbook, with `blockers` (what approval would refuse, such as `Add funds`) and the `approvalUrl` to hand to a person. When auto-approve is on, `autoApprove` says `scheduled` or `waiting` with the `reason`. Filter by `campaignId`. Returns the whole list (MCP `list_queue` pages it with `limit` and `cursor`). Agents never approve.",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "campaignId",
            "in": "query",
            "required": false,
            "description": "Only this playbook (cmp_).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [QueueItem]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QueueItemListResponse"
                },
                "examples": {
                  "waiting": {
                    "summary": "Two people waiting: one over the per-gift limit, one blocked on funds",
                    "value": {
                      "data": [
                        {
                          "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "campaignName": "New VP of Sales welcome",
                          "productId": "gtm-personalized-team-candle-v1",
                          "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                          "recipient": {
                            "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                            "name": "Jamie Chen",
                            "email": "jamie@northstar.example",
                            "company": "Northstar",
                            "title": "VP of Sales",
                            "sourceSystem": "hubspot",
                            "externalId": "contact-4821",
                            "country": "US",
                            "addressMode": "confirm"
                          },
                          "message": "Congrats on the new role, Jamie. Here's to what you build next.",
                          "priceCents": 3300,
                          "blockers": [],
                          "approvalUrl": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "autoApprove": {
                            "state": "waiting",
                            "reason": "over_gift_limit"
                          }
                        },
                        {
                          "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "campaignName": "New VP of Sales welcome",
                          "productId": "gtm-personalized-team-candle-v1",
                          "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                          "recipient": {
                            "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                            "name": "Priya Patel",
                            "email": "priya@lumen.example",
                            "company": "Lumen",
                            "sourceSystem": "salesforce",
                            "externalId": "003Hs00001XyZ",
                            "address": "500 Congress Ave",
                            "city": "Austin",
                            "state": "TX",
                            "zip": "78701",
                            "country": "US",
                            "addressMode": "known"
                          },
                          "message": "Congrats on the new role, Priya. Here's to what you build next.",
                          "priceCents": 3300,
                          "blockers": ["Add funds"],
                          "approvalUrl": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "autoApprove": {
                            "state": "waiting",
                            "reason": "low_balance"
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestQueueFilter"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/queue/skipped": {
      "get": {
        "operationId": "listSkipped",
        "tags": ["Queue & balance"],
        "summary": "List skipped people whose skip can be undone",
        "description": "People a person skipped in an active playbook, newest first (at most 500). A signed-in owner or admin can undo a skip; do not re-add skipped people.",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "campaignId",
            "in": "query",
            "required": false,
            "description": "Only this playbook (cmp_).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [SkippedPerson]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SkippedPersonListResponse"
                },
                "examples": {
                  "one": {
                    "summary": "One skipped person",
                    "value": {
                      "data": [
                        {
                          "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "campaignName": "New VP of Sales welcome",
                          "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                          "recipient": {
                            "name": "Priya Patel",
                            "company": "Lumen"
                          },
                          "reason": "Already a customer",
                          "skippedAt": "2026-10-11T15:04:05.000Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestQueueFilter"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/queue/approve": {
      "post": {
        "operationId": "approveGift",
        "tags": ["Queue & balance", "Human only"],
        "summary": "Approve one waiting gift",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Hand the item's `approvalUrl` to them. Approving charges the workspace balance and prepares the gift; `approveRepeat:true` also approves someone gifted by another campaign.",
        "x-mcp-tool": "approve_gift",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaignId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Campaign ID (cmp_): a saved campaign or playbook.",
                    "pattern": "^cmp_[A-Za-z0-9_-]+$"
                  },
                  "recipientId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "Stable workspace recipient ID; never infer from a name."
                  },
                  "approveRepeat": {
                    "type": "boolean",
                    "description": "True also approves another gift for someone who already received one from another campaign."
                  }
                },
                "required": ["campaignId", "recipientId"],
                "additionalProperties": false
              },
              "examples": {
                "approve": {
                  "summary": "Approve one waiting person",
                  "value": {
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Send}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResponse"
                },
                "examples": {
                  "send": {
                    "summary": "The prepared gift, paid from the balance",
                    "value": {
                      "data": {
                        "id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "productId": "gtm-personalized-team-candle-v1",
                        "recipient": {
                          "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                          "name": "Jamie Chen",
                          "email": "jamie@northstar.example",
                          "company": "Northstar",
                          "title": "VP of Sales",
                          "sourceSystem": "hubspot",
                          "externalId": "contact-4821",
                          "country": "US",
                          "addressMode": "confirm"
                        },
                        "message": "Congrats on the new role, Jamie. Here's to what you build next.",
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "meetingUrl": "",
                        "totalCents": 3300,
                        "status": "awaiting_address",
                        "outcome": "none",
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "testMode": true,
                        "attribution": {},
                        "giftLink": {
                          "state": "unclaimed",
                          "generation": 1,
                          "expiresAt": "2026-10-25T15:04:05.000Z"
                        },
                        "events": [
                          {
                            "status": "awaiting_address",
                            "at": "2026-10-11T15:04:05.000Z",
                            "note": "Gift prepared. Share the private address link yourself; no email was sent."
                          }
                        ],
                        "fundedBy": "balance"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Payment required: `INSUFFICIENT_BALANCE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "INSUFFICIENT_BALANCE": {
                    "$ref": "#/components/examples/INSUFFICIENT_BALANCE"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManagerQueue"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaignOrRecipient"
          },
          "409": {
            "description": "Conflict: `NOT_ALWAYS_ON`, `PLAYBOOK_OFF`, `CHECKOUT_REQUIRED`, `RECIPIENT_SKIPPED`, `REPEAT_REVIEW_REQUIRED`, `BUDGET_CAP`, `LIVE_ADDRESSLESS_UNAVAILABLE`, `ALREADY_APPROVED`, `BALANCE_CHANGED`, `PLAYBOOK_BUSY`, `GIFT_RETIRED`, `GIFT_UNAVAILABLE`, `PRICE_QUOTE_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "QUEUE_NOT_ALWAYS_ON": {
                    "$ref": "#/components/examples/QUEUE_NOT_ALWAYS_ON"
                  },
                  "QUEUE_PLAYBOOK_OFF": {
                    "$ref": "#/components/examples/QUEUE_PLAYBOOK_OFF"
                  },
                  "CHECKOUT_REQUIRED": {
                    "$ref": "#/components/examples/CHECKOUT_REQUIRED"
                  },
                  "RECIPIENT_SKIPPED": {
                    "$ref": "#/components/examples/RECIPIENT_SKIPPED"
                  },
                  "REPEAT_REVIEW_REQUIRED": {
                    "$ref": "#/components/examples/REPEAT_REVIEW_REQUIRED_QUEUE"
                  },
                  "BUDGET_CAP": {
                    "$ref": "#/components/examples/BUDGET_CAP"
                  },
                  "LIVE_ADDRESSLESS_UNAVAILABLE": {
                    "$ref": "#/components/examples/LIVE_ADDRESSLESS_UNAVAILABLE"
                  },
                  "ALREADY_APPROVED": {
                    "$ref": "#/components/examples/ALREADY_APPROVED"
                  },
                  "BALANCE_CHANGED": {
                    "$ref": "#/components/examples/BALANCE_CHANGED"
                  },
                  "PLAYBOOK_BUSY": {
                    "$ref": "#/components/examples/PLAYBOOK_BUSY"
                  },
                  "GIFT_RETIRED": {
                    "$ref": "#/components/examples/GIFT_RETIRED"
                  },
                  "GIFT_UNAVAILABLE": {
                    "$ref": "#/components/examples/GIFT_UNAVAILABLE"
                  },
                  "PRICE_QUOTE_REQUIRED": {
                    "$ref": "#/components/examples/PRICE_QUOTE_REQUIRED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/queue/skip": {
      "post": {
        "operationId": "skipGift",
        "tags": ["Queue & balance", "Human only"],
        "summary": "Skip one waiting person",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. A skip can be undone with `POST /queue/unskip`.",
        "x-mcp-tool": "skip_gift",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaignId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Campaign ID (cmp_): a saved campaign or playbook.",
                    "pattern": "^cmp_[A-Za-z0-9_-]+$"
                  },
                  "recipientId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "Stable workspace recipient ID; never infer from a name."
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Short optional reason for skipping, shown in the audit trail."
                  }
                },
                "required": ["campaignId", "recipientId"],
                "additionalProperties": false
              },
              "examples": {
                "skip": {
                  "summary": "Skip with a reason",
                  "value": {
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                    "reason": "Already a customer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": SkipResult}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SkipResultResponse"
                },
                "examples": {
                  "skipped": {
                    "summary": "Skipped",
                    "value": {
                      "data": {
                        "skipped": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManagerQueue"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaignOrRecipient"
          },
          "409": {
            "description": "Conflict: `NOT_ALWAYS_ON`, `PLAYBOOK_OFF`, `CHECKOUT_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "QUEUE_NOT_ALWAYS_ON": {
                    "$ref": "#/components/examples/QUEUE_NOT_ALWAYS_ON"
                  },
                  "QUEUE_PLAYBOOK_OFF": {
                    "$ref": "#/components/examples/QUEUE_PLAYBOOK_OFF"
                  },
                  "CHECKOUT_REQUIRED": {
                    "$ref": "#/components/examples/CHECKOUT_REQUIRED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/queue/unskip": {
      "post": {
        "operationId": "unskipGift",
        "tags": ["Queue & balance", "Human only"],
        "summary": "Undo a skip",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. The person waits in the queue again.",
        "x-mcp-tool": "unskip_gift",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaignId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Campaign ID (cmp_): a saved campaign or playbook.",
                    "pattern": "^cmp_[A-Za-z0-9_-]+$"
                  },
                  "recipientId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "Stable workspace recipient ID; never infer from a name."
                  }
                },
                "required": ["campaignId", "recipientId"],
                "additionalProperties": false
              },
              "examples": {
                "unskip": {
                  "summary": "Undo one skip",
                  "value": {
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": SkipResult}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SkipResultResponse"
                },
                "examples": {
                  "waiting": {
                    "summary": "Waiting again",
                    "value": {
                      "data": {
                        "skipped": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManagerQueue"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaignOrRecipient"
          },
          "409": {
            "description": "Conflict: `NOT_ALWAYS_ON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "QUEUE_NOT_ALWAYS_ON": {
                    "$ref": "#/components/examples/QUEUE_NOT_ALWAYS_ON"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/balance": {
      "get": {
        "operationId": "getBalance",
        "tags": ["Queue & balance"],
        "summary": "Read the gift balance",
        "description": "The balance in the workspace's mode (test money never pays for live gifts). When `lowBalance` is true, or a person waits with reason `low_balance`, hand `topUpUrl` to a person to add funds.",
        "x-mcp-tool": "get_balance",
        "x-agent-callable": true,
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Balance}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceResponse"
                },
                "examples": {
                  "ok": {
                    "summary": "Enough for everyone waiting",
                    "value": {
                      "data": {
                        "cents": 46700,
                        "mode": "test",
                        "lowBalance": false,
                        "topUpUrl": "https://gtmswag.com/settings?tab=billing"
                      }
                    }
                  },
                  "low": {
                    "summary": "Low: hand topUpUrl to a person",
                    "value": {
                      "data": {
                        "cents": 1200,
                        "mode": "test",
                        "lowBalance": true,
                        "topUpUrl": "https://gtmswag.com/settings?tab=billing"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/balance/ledger": {
      "get": {
        "operationId": "listBalanceLedger",
        "tags": ["Queue & balance"],
        "summary": "List balance movements, newest first",
        "description": "Top-ups, debits for approved gifts, credits for cancelled ones and adjustments, in the workspace's mode. `cents` is always positive; `kind` gives the direction. Not paginated beyond `limit`.",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many movements to return, 1 to 200 (default 50).",
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            },
            "example": 50
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [BalanceMovement]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceMovementListResponse"
                },
                "examples": {
                  "recent": {
                    "summary": "A debit for one auto-approved gift after a top-up",
                    "value": {
                      "data": [
                        {
                          "id": "bal_3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e",
                          "kind": "debit",
                          "cents": 3300,
                          "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                          "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "note": null,
                          "createdAt": "2026-10-11T15:04:05.000Z"
                        },
                        {
                          "id": "bal_8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d",
                          "kind": "topup",
                          "cents": 50000,
                          "sendId": null,
                          "campaignId": null,
                          "note": null,
                          "createdAt": "2026-10-01T12:00:00.000Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_listBalanceLedger"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/balance/topup": {
      "post": {
        "operationId": "createBalanceTopup",
        "tags": ["Queue & balance", "Human only"],
        "summary": "Start a balance top-up",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Hand `topUpUrl` from `GET /balance` to them. Returns the Stripe payment URL a person opens; the credit lands once payment completes.",
        "x-mcp-tool": "create_balance_topup",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cents": {
                    "type": "integer",
                    "minimum": 2500,
                    "maximum": 2000000,
                    "description": "Top-up amount in US cents, 2500 to 2000000."
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 150,
                    "description": "Same key for identical retries only."
                  }
                },
                "required": ["cents", "idempotencyKey"],
                "additionalProperties": false
              },
              "examples": {
                "topup": {
                  "summary": "Add $500",
                  "value": {
                    "cents": 50000,
                    "idempotencyKey": "topup-2026-10-11-alex"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": TopUpSession}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TopUpSessionResponse"
                },
                "examples": {
                  "url": {
                    "summary": "The payment page to open",
                    "value": {
                      "data": {
                        "url": "https://checkout.stripe.com/c/pay/cs_test_a1B2c3D4e5F6",
                        "sessionId": "cs_test_a1B2c3D4e5F6"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManagerWorkspace"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "Upstream error: `PAYMENT_UNAVAILABLE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "PAYMENT_UNAVAILABLE": {
                    "$ref": "#/components/examples/PAYMENT_UNAVAILABLE"
                  }
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/UnavailableStripe"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends": {
      "get": {
        "operationId": "listSends",
        "tags": ["Gifts"],
        "summary": "List gifts",
        "description": "Every gift (send) in the workspace or one campaign, newest first, with its immutable mode (`testMode`), status, outcome and timeline. Not paginated; for a paged, privacy-minimized status view use `GET /tracking`.",
        "x-mcp-tool": "list_sends",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "campaignId",
            "in": "query",
            "required": false,
            "description": "Campaign ID (cmp_): a saved campaign or playbook.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100,
              "pattern": "^cmp_[A-Za-z0-9_-]+$"
            },
            "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [Send]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendListResponse"
                },
                "examples": {
                  "one": {
                    "summary": "One auto-approved gift",
                    "value": {
                      "data": [
                        {
                          "id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                          "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "productId": "gtm-personalized-team-candle-v1",
                          "recipient": {
                            "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                            "name": "Jamie Chen",
                            "email": "jamie@northstar.example",
                            "company": "Northstar",
                            "title": "VP of Sales",
                            "sourceSystem": "hubspot",
                            "externalId": "contact-4821",
                            "country": "US",
                            "addressMode": "confirm"
                          },
                          "message": "Congrats on the new role, Jamie. Here's to what you build next.",
                          "senderName": "Alex Kim",
                          "senderCompany": "Acme",
                          "meetingUrl": "",
                          "totalCents": 3300,
                          "status": "awaiting_address",
                          "outcome": "none",
                          "createdAt": "2026-10-11T15:04:05.000Z",
                          "testMode": true,
                          "attribution": {},
                          "giftLink": {
                            "state": "unclaimed",
                            "generation": 1,
                            "expiresAt": "2026-10-25T15:04:05.000Z"
                          },
                          "events": [
                            {
                              "status": "awaiting_address",
                              "at": "2026-10-11T15:04:05.000Z",
                              "note": "Gift prepared. Share the private address link yourself; no email was sent."
                            }
                          ],
                          "fundedBy": "balance",
                          "autoApproved": true
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "commitSend",
        "tags": ["Gifts", "Human only"],
        "summary": "Commit a quoted gift",
        "description": "Human only: A signed-in teammate does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Commits a quote with an `idempotencyKey` within the approved campaign. Paid campaigns prepare gifts on their own after payment; playbook gifts go through approval (409 APPROVAL_REQUIRED). The body is validated first, so a key with an invalid body gets 400 before 403.",
        "x-mcp-tool": "commit_send",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "attribution": {
                    "$ref": "#/components/schemas/Attribution"
                  },
                  "productId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Current catalog gift ID; never invented."
                  },
                  "recipient": {
                    "$ref": "#/components/schemas/RecipientInput",
                    "description": "Gift recipient, delivery details and personal note."
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Printed note and recipient fallback."
                  },
                  "senderName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Gift sender's name."
                  },
                  "senderCompany": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Gift sender's company."
                  },
                  "meetingUrl": {
                    "$ref": "#/components/schemas/UrlOrEmpty",
                    "description": "Optional meeting URL; empty string clears it."
                  },
                  "campaignId": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Campaign ID (cmp_): a saved campaign or playbook.",
                    "pattern": "^cmp_[A-Za-z0-9_-]+$"
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 150,
                    "description": "Same key for identical retries only."
                  },
                  "customization": {
                    "$ref": "#/components/schemas/Customization"
                  },
                  "quoteId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Quote ID (quo_): a saved send quote.",
                    "pattern": "^quo_[A-Za-z0-9_-]+$"
                  }
                },
                "required": [
                  "productId",
                  "recipient",
                  "message",
                  "senderName",
                  "senderCompany",
                  "idempotencyKey",
                  "quoteId"
                ],
                "additionalProperties": false
              },
              "examples": {
                "commit": {
                  "summary": "Commit a quote (signed-in person)",
                  "value": {
                    "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                    "quoteId": "quo_5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a",
                    "idempotencyKey": "q4-champions-priya-patel",
                    "productId": "gtm-personalized-team-candle-v1",
                    "recipient": {
                      "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                      "name": "Priya Patel",
                      "email": "priya@lumen.example",
                      "company": "Lumen",
                      "sourceSystem": "salesforce",
                      "externalId": "003Hs00001XyZ",
                      "address": "500 Congress Ave",
                      "city": "Austin",
                      "state": "TX",
                      "zip": "78701",
                      "country": "US",
                      "addressMode": "known"
                    },
                    "message": "Thank you for championing us this year, Priya.",
                    "senderName": "Alex Kim",
                    "senderCompany": "Acme"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success: `{\"data\": Send}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResponse"
                },
                "examples": {
                  "send": {
                    "summary": "The new gift",
                    "value": {
                      "data": {
                        "id": "send_7d9f1b3d5f7a9c1e3b5d7f9a1c3e5a7b",
                        "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                        "productId": "gtm-personalized-team-candle-v1",
                        "recipient": {
                          "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                          "name": "Priya Patel",
                          "email": "priya@lumen.example",
                          "company": "Lumen",
                          "sourceSystem": "salesforce",
                          "externalId": "003Hs00001XyZ",
                          "address": "500 Congress Ave",
                          "city": "Austin",
                          "state": "TX",
                          "zip": "78701",
                          "country": "US",
                          "addressMode": "known"
                        },
                        "message": "Thank you for championing us this year, Priya.",
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "meetingUrl": "",
                        "totalCents": 3300,
                        "status": "queued",
                        "outcome": "none",
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "testMode": true,
                        "attribution": {},
                        "events": [
                          {
                            "status": "queued",
                            "at": "2026-10-11T15:04:05.000Z",
                            "note": "Gift queued."
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `CAMPAIGN_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
                  },
                  "CAMPAIGN_REQUIRED": {
                    "$ref": "#/components/examples/CAMPAIGN_REQUIRED"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "QUOTE_NOT_FOUND": {
                    "$ref": "#/components/examples/QUOTE_NOT_FOUND"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict: `IDEMPOTENCY_CONFLICT`, `QUOTE_EXPIRED`, `QUOTE_CHANGED`, `MODE_CHANGED`, `APPROVAL_REQUIRED`, `POLICY_CHANGED`, `CAMPAIGN_PAYMENT_REQUIRED`, `DUPLICATE_SEND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "SEND_IDEMPOTENCY_CONFLICT": {
                    "$ref": "#/components/examples/SEND_IDEMPOTENCY_CONFLICT"
                  },
                  "QUOTE_EXPIRED": {
                    "$ref": "#/components/examples/QUOTE_EXPIRED"
                  },
                  "QUOTE_CHANGED": {
                    "$ref": "#/components/examples/QUOTE_CHANGED"
                  },
                  "MODE_CHANGED": {
                    "$ref": "#/components/examples/MODE_CHANGED"
                  },
                  "APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/APPROVAL_REQUIRED_WORKSPACE"
                  },
                  "POLICY_CHANGED": {
                    "$ref": "#/components/examples/POLICY_CHANGED"
                  },
                  "CAMPAIGN_PAYMENT_REQUIRED": {
                    "$ref": "#/components/examples/CAMPAIGN_PAYMENT_REQUIRED_WORKSPACE"
                  },
                  "DUPLICATE_SEND": {
                    "$ref": "#/components/examples/DUPLICATE_SEND"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}": {
      "get": {
        "operationId": "getSend",
        "tags": ["Gifts"],
        "summary": "Read one gift",
        "description": "One gift's detail, timeline and recipient-photo review state (`portrait`). A staff-sourced photo needs the customer's explicit approval before production.",
        "x-mcp-tool": "get_send",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Send}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResponse"
                },
                "examples": {
                  "send": {
                    "summary": "An auto-approved gift",
                    "value": {
                      "data": {
                        "id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "productId": "gtm-personalized-team-candle-v1",
                        "recipient": {
                          "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                          "name": "Jamie Chen",
                          "email": "jamie@northstar.example",
                          "company": "Northstar",
                          "title": "VP of Sales",
                          "sourceSystem": "hubspot",
                          "externalId": "contact-4821",
                          "country": "US",
                          "addressMode": "confirm"
                        },
                        "message": "Congrats on the new role, Jamie. Here's to what you build next.",
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "meetingUrl": "",
                        "totalCents": 3300,
                        "status": "awaiting_address",
                        "outcome": "none",
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "testMode": true,
                        "attribution": {},
                        "giftLink": {
                          "state": "unclaimed",
                          "generation": 1,
                          "expiresAt": "2026-10-25T15:04:05.000Z"
                        },
                        "events": [
                          {
                            "status": "awaiting_address",
                            "at": "2026-10-11T15:04:05.000Z",
                            "note": "Gift prepared. Share the private address link yourself; no email was sent."
                          }
                        ],
                        "fundedBy": "balance",
                        "autoApproved": true
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundSend"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "operationId": "updateSend",
        "tags": ["Gifts"],
        "summary": "Record an outcome (legacy) or change a test gift's status",
        "description": "Keys may set `outcome` only; prefer `POST /sends/{id}/outcomes`, which deduplicates. Changing `status` needs a signed-in person (keys get 403 HUMAN_APPROVAL_REQUIRED) and only follows the allowed steps on test gifts; live fulfillment status is managed by operations (403 LIVE_STATUS_PROTECTED).",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "queued",
                      "in_production",
                      "shipped",
                      "delivered",
                      "cancelled"
                    ],
                    "description": "Test gifts only, signed-in people only: the next fulfillment step."
                  },
                  "outcome": {
                    "type": "string",
                    "enum": [
                      "none",
                      "replied",
                      "meeting_booked",
                      "meeting_held"
                    ],
                    "description": "Customer-reported result; never infer it from delivery."
                  }
                },
                "additionalProperties": false
              },
              "examples": {
                "outcome": {
                  "summary": "The customer reported a meeting",
                  "value": {
                    "outcome": "meeting_booked"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Send}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResponse"
                },
                "examples": {
                  "send": {
                    "summary": "The gift with its outcome",
                    "value": {
                      "data": {
                        "id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "productId": "gtm-personalized-team-candle-v1",
                        "recipient": {
                          "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                          "name": "Jamie Chen",
                          "email": "jamie@northstar.example",
                          "company": "Northstar",
                          "title": "VP of Sales",
                          "sourceSystem": "hubspot",
                          "externalId": "contact-4821",
                          "country": "US",
                          "addressMode": "confirm"
                        },
                        "message": "Congrats on the new role, Jamie. Here's to what you build next.",
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "meetingUrl": "",
                        "totalCents": 3300,
                        "status": "awaiting_address",
                        "outcome": "meeting_booked",
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "testMode": true,
                        "attribution": {},
                        "giftLink": {
                          "state": "unclaimed",
                          "generation": 1,
                          "expiresAt": "2026-10-25T15:04:05.000Z"
                        },
                        "events": [
                          {
                            "status": "awaiting_address",
                            "at": "2026-10-11T15:04:05.000Z",
                            "note": "Gift prepared. Share the private address link yourself; no email was sent."
                          }
                        ],
                        "fundedBy": "balance",
                        "autoApproved": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `LIVE_STATUS_PROTECTED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
                  },
                  "LIVE_STATUS_PROTECTED": {
                    "$ref": "#/components/examples/LIVE_STATUS_PROTECTED"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundSend"
          },
          "409": {
            "description": "Conflict: `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "STATUS_CHANGE_UNAVAILABLE": {
                    "$ref": "#/components/examples/STATUS_CHANGE_UNAVAILABLE"
                  },
                  "SEND_CHANGED": {
                    "$ref": "#/components/examples/SEND_CHANGED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/quotes": {
      "post": {
        "operationId": "createQuote",
        "tags": ["Gifts"],
        "summary": "Quote one gift on an approved campaign",
        "description": "Validates one roster person of an active batch or single campaign against its approved policy and saves a 15-minute quote. A quote never sends or pays; committing it needs a signed-in person. Playbook gifts go through `POST /playbooks/{id}/people` instead. In a live workspace an unknown address (`addressMode:\"confirm\"`) refuses with 409 LIVE_ADDRESSLESS_UNAVAILABLE.",
        "x-mcp-tool": "quote_send",
        "x-agent-callable": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "attribution": {
                    "$ref": "#/components/schemas/Attribution"
                  },
                  "productId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Current catalog gift ID; never invented."
                  },
                  "recipient": {
                    "$ref": "#/components/schemas/RecipientInput",
                    "description": "Gift recipient, delivery details and personal note."
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Printed note and recipient fallback."
                  },
                  "senderName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Gift sender's name."
                  },
                  "senderCompany": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Gift sender's company."
                  },
                  "meetingUrl": {
                    "$ref": "#/components/schemas/UrlOrEmpty",
                    "description": "Optional meeting URL; empty string clears it."
                  },
                  "campaignId": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Campaign ID (cmp_): a saved campaign or playbook.",
                    "pattern": "^cmp_[A-Za-z0-9_-]+$"
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 150,
                    "description": "Same key for identical retries only."
                  },
                  "customization": {
                    "$ref": "#/components/schemas/Customization"
                  }
                },
                "required": [
                  "productId",
                  "recipient",
                  "message",
                  "senderName",
                  "senderCompany"
                ],
                "additionalProperties": false
              },
              "examples": {
                "quote": {
                  "summary": "Quote the roster person of an active batch campaign",
                  "value": {
                    "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                    "productId": "gtm-personalized-team-candle-v1",
                    "recipient": {
                      "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                      "name": "Priya Patel",
                      "email": "priya@lumen.example",
                      "company": "Lumen",
                      "sourceSystem": "salesforce",
                      "externalId": "003Hs00001XyZ",
                      "address": "500 Congress Ave",
                      "city": "Austin",
                      "state": "TX",
                      "zip": "78701",
                      "country": "US",
                      "addressMode": "known"
                    },
                    "message": "Thank you for championing us this year, Priya.",
                    "senderName": "Alex Kim",
                    "senderCompany": "Acme"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success: `{\"data\": Quote}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteResponse"
                },
                "examples": {
                  "quote": {
                    "summary": "A 15-minute quote",
                    "value": {
                      "data": {
                        "id": "quo_5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a",
                        "attribution": {},
                        "subtotalCents": 3300,
                        "shippingCents": 0,
                        "taxCents": 0,
                        "totalCents": 3300,
                        "expiresAt": "2026-10-11T15:19:05.000Z",
                        "testMode": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `PORTRAIT_REQUIRED`, `ADULT_RECIPIENT_REQUIRED`, `PERSONALIZATION_REQUIRED`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "PORTRAIT_REQUIRED": {
                    "$ref": "#/components/examples/PORTRAIT_REQUIRED"
                  },
                  "ADULT_RECIPIENT_REQUIRED": {
                    "$ref": "#/components/examples/ADULT_RECIPIENT_REQUIRED"
                  },
                  "PERSONALIZATION_REQUIRED": {
                    "$ref": "#/components/examples/PERSONALIZATION_REQUIRED"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `CAMPAIGN_REQUIRED`, `LIVE_NOT_READY`, `ARTWORK_UNAVAILABLE`, `POLICY_VIOLATION`, `RECIPIENT_SCOPE`, `MESSAGE_POLICY`, `CUSTOMIZATION_POLICY`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "CAMPAIGN_REQUIRED": {
                    "$ref": "#/components/examples/CAMPAIGN_REQUIRED"
                  },
                  "LIVE_NOT_READY": {
                    "$ref": "#/components/examples/LIVE_NOT_READY"
                  },
                  "ARTWORK_UNAVAILABLE": {
                    "$ref": "#/components/examples/ARTWORK_UNAVAILABLE"
                  },
                  "POLICY_VIOLATION": {
                    "$ref": "#/components/examples/POLICY_VIOLATION"
                  },
                  "ROSTER_SCOPE": {
                    "$ref": "#/components/examples/ROSTER_SCOPE"
                  },
                  "MESSAGE_POLICY": {
                    "$ref": "#/components/examples/MESSAGE_POLICY"
                  },
                  "CUSTOMIZATION_POLICY": {
                    "$ref": "#/components/examples/CUSTOMIZATION_POLICY"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `LIVE_ADDRESSLESS_UNAVAILABLE`, `CAMPAIGN_INACTIVE`, `BUDGET_EXCEEDED`, `COUNT_EXCEEDED`, `QUOTE_CHANGED`, `GIFT_RETIRED`, `GIFT_UNAVAILABLE`, `PRICE_QUOTE_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "LIVE_ADDRESSLESS_UNAVAILABLE": {
                    "$ref": "#/components/examples/LIVE_ADDRESSLESS_UNAVAILABLE"
                  },
                  "CAMPAIGN_INACTIVE": {
                    "$ref": "#/components/examples/CAMPAIGN_INACTIVE"
                  },
                  "BUDGET_EXCEEDED": {
                    "$ref": "#/components/examples/BUDGET_EXCEEDED"
                  },
                  "COUNT_EXCEEDED": {
                    "$ref": "#/components/examples/COUNT_EXCEEDED"
                  },
                  "QUOTE_CHANGED": {
                    "$ref": "#/components/examples/QUOTE_CHANGED"
                  },
                  "GIFT_RETIRED": {
                    "$ref": "#/components/examples/GIFT_RETIRED"
                  },
                  "GIFT_UNAVAILABLE": {
                    "$ref": "#/components/examples/GIFT_UNAVAILABLE"
                  },
                  "PRICE_QUOTE_REQUIRED": {
                    "$ref": "#/components/examples/PRICE_QUOTE_REQUIRED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}/photo": {
      "post": {
        "operationId": "updateRecipientPhoto",
        "tags": ["Gifts"],
        "summary": "Approve, replace or reject a recipient photo",
        "description": "For gifts that print a recipient portrait, before fulfillment locks. Send the gift's current `portrait.version`. `approve` (a staff-sourced photo) and `replace` with a URL import need the customer's explicit permission (`rightsConfirmed:true`); never infer it. API keys may call this; OAuth connections cannot.",
        "x-mcp-tool": "update_recipient_photo",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecipientPhotoChange"
              },
              "examples": {
                "replace": {
                  "summary": "Replace with an uploaded portrait",
                  "value": {
                    "version": 1,
                    "action": "replace",
                    "assetId": "asset_9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d",
                    "rightsConfirmed": true
                  }
                },
                "approve": {
                  "summary": "Approve the sourced photo (customer authorized)",
                  "value": {
                    "version": 2,
                    "action": "approve",
                    "rightsConfirmed": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Send}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResponse"
                },
                "examples": {
                  "approved": {
                    "summary": "The gift with its approved portrait",
                    "value": {
                      "data": {
                        "id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "productId": "gtm-photo-bobblehead-v1",
                        "recipient": {
                          "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                          "name": "Jamie Chen",
                          "email": "jamie@northstar.example",
                          "company": "Northstar",
                          "title": "VP of Sales",
                          "sourceSystem": "hubspot",
                          "externalId": "contact-4821",
                          "country": "US",
                          "addressMode": "confirm",
                          "photo": {
                            "source": "upload",
                            "assetId": "asset_9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d"
                          }
                        },
                        "message": "Congrats on the new role, Jamie. Here's to what you build next.",
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "meetingUrl": "",
                        "totalCents": 9100,
                        "status": "awaiting_address",
                        "outcome": "none",
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "testMode": true,
                        "attribution": {},
                        "giftLink": {
                          "state": "unclaimed",
                          "generation": 1,
                          "expiresAt": "2026-10-25T15:04:05.000Z"
                        },
                        "events": [
                          {
                            "status": "awaiting_address",
                            "at": "2026-10-11T15:04:05.000Z",
                            "note": "Gift prepared. Share the private address link yourself; no email was sent."
                          }
                        ],
                        "fundedBy": "balance",
                        "autoApproved": true,
                        "portrait": {
                          "state": "approved",
                          "version": 2,
                          "assetId": "asset_9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d",
                          "approvedAt": "2026-10-11T15:04:05.000Z"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `INVALID_REQUEST`, `PORTRAIT_RESOLUTION`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "NO_PORTRAIT": {
                    "$ref": "#/components/examples/NO_PORTRAIT"
                  },
                  "PORTRAIT_RESOLUTION": {
                    "$ref": "#/components/examples/PORTRAIT_RESOLUTION"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenArtwork"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundGift"
          },
          "409": {
            "description": "Conflict: `PHOTO_LOCKED`, `PHOTO_CHANGED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "PHOTO_LOCKED": {
                    "$ref": "#/components/examples/PHOTO_LOCKED"
                  },
                  "PHOTO_CHANGED": {
                    "$ref": "#/components/examples/PHOTO_CHANGED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "description": "Unsupported media type: `PORTRAIT_IMAGE_REQUIRED`, `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "PORTRAIT_IMAGE_REQUIRED": {
                    "$ref": "#/components/examples/PORTRAIT_IMAGE_REQUIRED"
                  },
                  "JSON_REQUIRED": {
                    "$ref": "#/components/examples/JSON_REQUIRED"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/personalize": {
      "post": {
        "operationId": "personalizeNote",
        "tags": ["Gifts"],
        "summary": "Draft a printed note for one person",
        "description": "Suggests a short printed note from the gift's template, or from AI within a daily allowance (`source` says which). It saves nothing; put the text in `message` yourself after the customer agrees.",
        "x-agent-callable": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "productId": {
                    "type": "string",
                    "description": "Current catalog gift ID."
                  },
                  "recipient": {
                    "$ref": "#/components/schemas/RecipientInput",
                    "description": "The person the note is for; name, company and title help."
                  },
                  "angle": {
                    "default": "",
                    "type": "string",
                    "maxLength": 500,
                    "description": "What the note should mention, in a few words."
                  },
                  "tone": {
                    "default": "warm",
                    "type": "string",
                    "enum": ["warm", "concise", "playful", "professional"],
                    "description": "Voice of the note."
                  }
                },
                "required": ["productId", "recipient"],
                "additionalProperties": false
              },
              "examples": {
                "note": {
                  "summary": "A concise note for a new VP",
                  "value": {
                    "productId": "gtm-personalized-team-candle-v1",
                    "recipient": {
                      "name": "Jamie Chen",
                      "company": "Northstar",
                      "title": "VP of Sales"
                    },
                    "angle": "new role",
                    "tone": "concise"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": NoteSuggestion}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteSuggestionResponse"
                },
                "examples": {
                  "note": {
                    "summary": "A template note",
                    "value": {
                      "data": {
                        "message": "A little something for you, Jamie. I’d enjoy comparing notes.",
                        "source": "template"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenDemo"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundGift"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/distribution": {
      "get": {
        "operationId": "getGiftLinkRecords",
        "tags": ["Gift links"],
        "summary": "Read private gift links for matching",
        "description": "One page of a campaign's people with their private claim URL (`gift_link`, only when `availability` is `ready`), expiry and stable source IDs for matching into another system. Others carry `availability_reason`. Page with `limit` and `nextCursor` (null on the last page) and keep the same filters; `counts` cover the whole filtered set. A cursor from before a campaign change returns 409 CURSOR_STALE: start again. Reading never pays, sends, renews or rotates a link. Accepts an MCP OAuth token with `gifts:links:read`.",
        "x-mcp-tool": "get_gift_link_records",
        "x-agent-callable": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "mcpOAuth": ["gifts:links:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          },
          {
            "name": "recipientIds",
            "in": "query",
            "required": false,
            "description": "Explicit stable recipient IDs to select.",
            "style": "form",
            "explode": false,
            "schema": {
              "minItems": 1,
              "maxItems": 500,
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "example": ["recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a"]
          },
          {
            "name": "giftIds",
            "in": "query",
            "required": false,
            "description": "Explicit gift/send IDs to select.",
            "style": "form",
            "explode": false,
            "schema": {
              "minItems": 1,
              "maxItems": 500,
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "example": ["send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b"]
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Filter supplied recipient name, email, source ID, company or profile.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "northstar"
          },
          {
            "name": "availability",
            "in": "query",
            "required": false,
            "description": "Filter current link availability; ready means usable now.",
            "schema": {
              "type": "string",
              "enum": [
                "ready",
                "awaiting_approval",
                "preparing_links",
                "unavailable"
              ]
            },
            "example": "ready"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "nextCursor from the previous page; keep the same filters. Omit for the first page.",
            "schema": {
              "type": "string",
              "maxLength": 1500
            },
            "example": "eyJmIjoiOWMxZTNiNWQ3ZjlhMWMzZTViN2Q5ZjFhM2M1ZTdiOWQiLCJpIjo1MH0="
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum records in this page, from 1 to 100.",
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "example": 50
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": DistributionRecordsPage}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DistributionRecordsPageResponse"
                },
                "examples": {
                  "page": {
                    "summary": "One ready link",
                    "value": {
                      "data": {
                        "version": 1,
                        "records": [
                          {
                            "recipient_id": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                            "source_system": "hubspot",
                            "external_id": "contact-4821",
                            "name": "Jamie Chen",
                            "company": "Northstar",
                            "email": "jamie@northstar.example",
                            "profile_url": "",
                            "campaign_id": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                            "gift_id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                            "product_id": "gtm-personalized-team-candle-v1",
                            "gift_link": "https://gtmswag.com/confirm/9f2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d1f",
                            "gift_status": "awaiting_address",
                            "availability": "ready",
                            "availability_reason": "",
                            "gift_expires_at": "2026-10-25T15:04:05.000Z",
                            "link_generation": 1,
                            "mode": "test",
                            "import_id": "",
                            "import_row_id": "",
                            "review_url": "https://gtmswag.com/campaigns/cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
                          }
                        ],
                        "nextCursor": null,
                        "counts": {
                          "total": 1,
                          "ready": 1,
                          "unavailable": 0
                        },
                        "sourceImports": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenLinksScope"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `CURSOR_STALE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "CURSOR_STALE": {
                    "$ref": "#/components/examples/CURSOR_STALE"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/distribution/exports": {
      "post": {
        "operationId": "exportGiftLinks",
        "tags": ["Gift links"],
        "summary": "Create a gift-link CSV export",
        "description": "The website's bulk export: `scope` `all`, `selection` (`recipientIds` or `giftIds`) or `filtered`. By default it holds ready links plus the original source columns; `includeUnavailable:true` lists everyone for a status report. Returns the export ID, an authenticated `downloadUrl` (valid 24 hours), counts and exclusions. Creates an export record only. Accepts an MCP OAuth token with `gifts:links:read`.",
        "x-mcp-tool": "export_gift_links",
        "x-agent-callable": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "mcpOAuth": ["gifts:links:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipientIds": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    "description": "Explicit stable recipient IDs to select."
                  },
                  "giftIds": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    "description": "Explicit gift/send IDs to select."
                  },
                  "search": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Filter supplied recipient name, email, source ID, company or profile."
                  },
                  "availability": {
                    "type": "string",
                    "enum": [
                      "ready",
                      "awaiting_approval",
                      "preparing_links",
                      "unavailable"
                    ],
                    "description": "Filter current link availability; ready means usable now."
                  },
                  "scope": {
                    "type": "string",
                    "enum": ["all", "selection", "filtered"],
                    "description": "Explicit all, selection or filtered recipient scope."
                  },
                  "preset": {
                    "default": "original",
                    "type": "string",
                    "enum": ["original", "compact"],
                    "description": "original preserves selected source columns; compact exports gift-link identity columns."
                  },
                  "includeUnavailable": {
                    "default": false,
                    "type": "boolean",
                    "description": "True creates a full status report with blank unavailable links; false exports ready links only."
                  },
                  "columnPrefix": {
                    "type": "string",
                    "pattern": "^[a-zA-Z0-9_]{0,40}$",
                    "description": "Optional prefix for appended gift columns; collisions receive gtm_swag_ automatically."
                  },
                  "optionalColumns": {
                    "default": [],
                    "maxItems": 8,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "recipient_id",
                        "campaign_id",
                        "gift_id",
                        "source_system",
                        "external_id",
                        "profile_url",
                        "link_generation",
                        "availability_reason"
                      ]
                    },
                    "description": "Additional technical columns; default export has only gift_link, gift_status and gift_expires_at."
                  }
                },
                "required": ["scope"],
                "additionalProperties": false
              },
              "examples": {
                "all": {
                  "summary": "Every ready link with the original columns",
                  "value": {
                    "scope": "all"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success: `{\"data\": GiftLinkExport}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftLinkExportResponse"
                },
                "examples": {
                  "export": {
                    "summary": "The export to download",
                    "value": {
                      "data": {
                        "id": "export_4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c",
                        "downloadUrl": "https://gtmswag.com/api/v1/distribution/exports/export_4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c",
                        "filename": "gtm-swag-cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e-gift-links.csv",
                        "columns": [
                          "Name",
                          "Email",
                          "Company",
                          "gift_link",
                          "gift_status",
                          "gift_expires_at"
                        ],
                        "mode": "test",
                        "counts": {
                          "total": 1,
                          "ready": 1,
                          "unavailable": 0
                        },
                        "excluded": [],
                        "earliestExpiry": "2026-10-25T15:04:05.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenLinksScope"
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "NOT_FOUND": {
                    "$ref": "#/components/examples/NOT_FOUND"
                  },
                  "SELECTION_NOT_FOUND": {
                    "$ref": "#/components/examples/SELECTION_NOT_FOUND"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict: `IMPORT_INCOMPLETE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "EXPORT_IMPORT_INCOMPLETE": {
                    "$ref": "#/components/examples/EXPORT_IMPORT_INCOMPLETE"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/distribution/exports/{id}": {
      "get": {
        "operationId": "downloadGiftLinkExport",
        "tags": ["Gift links"],
        "summary": "Download a gift-link CSV",
        "description": "The CSV of an export from `POST /campaigns/{id}/distribution/exports`, rendered now: revoked or refund-locked links are removed. The file holds private links meant only for the workspace; keep it out of logs and public places. Exports expire after 24 hours. Accepts an MCP OAuth token with `gifts:links:read`.",
        "x-mcp-tool": "download_gift_link_export",
        "x-agent-callable": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "mcpOAuth": ["gifts:links:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ExportId"
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file (UTF-8, CRLF line endings).",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment; filename=\"…\"`.",
                "schema": {
                  "type": "string"
                },
                "example": "attachment; filename=\"gtm-swag-cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e-gift-links.csv\""
              }
            },
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "csv": {
                    "summary": "Original columns plus the gift columns",
                    "value": "Name,Email,Company,gift_link,gift_status,gift_expires_at\r\nJamie Chen,jamie@northstar.example,Northstar,https://gtmswag.com/confirm/9f2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d1f,awaiting_address,2026-10-25T15:04:05.000Z\r\n"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenLinksScope"
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "EXPORT_NOT_FOUND": {
                    "$ref": "#/components/examples/EXPORT_NOT_FOUND"
                  },
                  "NOT_FOUND": {
                    "$ref": "#/components/examples/NOT_FOUND"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/distribution/import-chunks": {
      "post": {
        "operationId": "uploadGiftSourceChunk",
        "tags": ["Gift links"],
        "summary": "Upload a large source import in parts",
        "description": "For a source import too large for `POST /campaigns/{id}/distribution/imports`: send the UTF-8 import JSON as base64 parts (up to 384, 150,000 bytes each before encoding). Keep `uploadId`, `partCount`, `totalBytes` and each part's bytes identical on retries. `complete` turns true once every part is saved and the import is validated; while another request assembles it the response carries `retryAfterMs` (resend the same last part after it). Uploads expire after 6 hours. Accepts an MCP OAuth token with `gifts:write`.",
        "x-mcp-tool": "upload_gift_source_chunk",
        "x-agent-callable": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "mcpOAuth": ["gifts:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "uploadId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Stable upload ID; reuse it with identical metadata and part bytes on retries."
                  },
                  "partIndex": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 383,
                    "description": "Zero-based part position; each UTF-8 byte segment is separately base64 encoded."
                  },
                  "partCount": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 384,
                    "description": "Total number of parts in this upload, from 1 to 384."
                  },
                  "data": {
                    "type": "string",
                    "minLength": 4,
                    "maxLength": 200000,
                    "description": "Canonical base64 for this part, at most 200000 ASCII characters; no data-URL prefix. Blank unselected cells before serializing the import JSON."
                  },
                  "totalBytes": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 33554432,
                    "description": "UTF-8 byte length of the complete serialized import JSON, at most 32 MiB."
                  }
                },
                "required": [
                  "uploadId",
                  "partIndex",
                  "partCount",
                  "data",
                  "totalBytes"
                ],
                "additionalProperties": false
              },
              "examples": {
                "part": {
                  "summary": "Part 1 of 3",
                  "value": {
                    "uploadId": "hubspot-export-2026-10-11-upload",
                    "partIndex": 0,
                    "partCount": 3,
                    "totalBytes": 412000,
                    "data": "eyJpbXBvcnRJZCI6Imh1YnNwb3QtZXhwb3J0LTIwMjYtMTAtMTEi"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": SourceUploadProgress}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SourceUploadProgressResponse"
                },
                "examples": {
                  "partial": {
                    "summary": "Part saved; more to send",
                    "value": {
                      "data": {
                        "uploadId": "hubspot-export-2026-10-11-upload",
                        "complete": false,
                        "receivedParts": 1,
                        "partCount": 3
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `UPLOAD_ENCODING_INVALID`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "UPLOAD_ENCODING_INVALID": {
                    "$ref": "#/components/examples/UPLOAD_ENCODING_INVALID"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `DEMO_LIMITED`, `INSUFFICIENT_SCOPE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "DEMO_LIMITED": {
                    "$ref": "#/components/examples/DEMO_LIMITED"
                  },
                  "UPLOAD_SCOPE": {
                    "$ref": "#/components/examples/UPLOAD_SCOPE"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "NOT_FOUND": {
                    "$ref": "#/components/examples/NOT_FOUND"
                  },
                  "UPLOAD_NOT_FOUND": {
                    "$ref": "#/components/examples/UPLOAD_NOT_FOUND"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict: `UPLOAD_CONFLICT`, `UPLOAD_SIZE_MISMATCH`, `IMPORT_CONFLICT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "UPLOAD_CONFLICT": {
                    "$ref": "#/components/examples/UPLOAD_CONFLICT"
                  },
                  "UPLOAD_SIZE_MISMATCH": {
                    "$ref": "#/components/examples/UPLOAD_SIZE_MISMATCH"
                  },
                  "IMPORT_CONFLICT": {
                    "$ref": "#/components/examples/IMPORT_CONFLICT"
                  }
                }
              }
            }
          },
          "410": {
            "description": "Gone: `UPLOAD_EXPIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "UPLOAD_EXPIRED": {
                    "$ref": "#/components/examples/UPLOAD_EXPIRED"
                  }
                }
              }
            }
          },
          "413": {
            "description": "Request too large: `IMPORT_SIZE_LIMIT`, `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "IMPORT_SIZE_LIMIT": {
                    "$ref": "#/components/examples/IMPORT_SIZE_LIMIT"
                  },
                  "REQUEST_TOO_LARGE": {
                    "$ref": "#/components/examples/REQUEST_TOO_LARGE"
                  }
                }
              }
            }
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "description": "Too many requests: `UPLOAD_CAPACITY`, `RATE_LIMIT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "UPLOAD_CAPACITY": {
                    "$ref": "#/components/examples/UPLOAD_CAPACITY"
                  },
                  "RATE_LIMIT": {
                    "$ref": "#/components/examples/RATE_LIMIT"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/distribution/imports": {
      "post": {
        "operationId": "saveRecipientImport",
        "tags": ["Gift links"],
        "summary": "Keep original source columns with recipients",
        "description": "Keeps only the columns you select (`retainedColumnIndices`) from the original CSV, linked to recipients by `importRowId` (and `recipientId`), so exports can return the customer's own columns. Rows may arrive across several calls; replays with identical rows are no-ops. No gifts, messages or charges. Accepts an MCP OAuth token with `gifts:write`.",
        "x-mcp-tool": "save_recipient_import",
        "x-agent-callable": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "mcpOAuth": ["gifts:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "importId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Stable customer import ID; reuse with identical retry data."
                  },
                  "headers": {
                    "minItems": 1,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Original source CSV headers in order, including duplicates."
                  },
                  "retainedColumnIndices": {
                    "minItems": 1,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 99
                    },
                    "description": "Original zero-based positions explicitly selected for private retention."
                  },
                  "rows": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "importRowId": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200,
                          "description": "Stable source row ID within an import."
                        },
                        "recipientId": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200,
                          "description": "Stable workspace recipient ID; never infer from a name."
                        },
                        "position": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 499,
                          "description": "Original zero-based row position in the import."
                        },
                        "cells": {
                          "maxItems": 100,
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Original untrimmed source cell values, aligned with headers."
                        },
                        "error": {
                          "type": "string",
                          "maxLength": 1000,
                          "description": "Validation error for an unmatched source row; no link will be assigned."
                        }
                      },
                      "required": ["importRowId", "position", "cells"],
                      "additionalProperties": false
                    },
                    "description": "Source rows linked by stable importRowId and recipientId; preserve original order and cells."
                  },
                  "totalRows": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 500,
                    "description": "Total source rows, at most 500; do not truncate."
                  },
                  "sourceBytes": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 5242880,
                    "description": "Original CSV bytes, at most 5 MiB."
                  }
                },
                "required": [
                  "importId",
                  "headers",
                  "retainedColumnIndices",
                  "rows",
                  "totalRows",
                  "sourceBytes"
                ],
                "additionalProperties": false
              },
              "examples": {
                "import": {
                  "summary": "Keep the Owner column for one row",
                  "value": {
                    "importId": "hubspot-export-2026-10-11",
                    "headers": ["Name", "Email", "Company", "Owner"],
                    "retainedColumnIndices": [3],
                    "rows": [
                      {
                        "importRowId": "row-1",
                        "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                        "position": 0,
                        "cells": [
                          "Jamie Chen",
                          "jamie@northstar.example",
                          "Northstar",
                          "Dana"
                        ]
                      }
                    ],
                    "totalRows": 1,
                    "sourceBytes": 92
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": SourceImport}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SourceImportResponse"
                },
                "examples": {
                  "saved": {
                    "summary": "The saved import",
                    "value": {
                      "data": {
                        "importId": "hubspot-export-2026-10-11",
                        "headers": ["Name", "Email", "Company", "Owner"],
                        "retainedColumnIndices": [3],
                        "totalRows": 1,
                        "complete": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `INVALID_REQUEST`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "IMPORT_INVALID": {
                    "$ref": "#/components/examples/IMPORT_INVALID"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `INSUFFICIENT_SCOPE`, `DEMO_LIMITED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "IMPORT_SCOPE": {
                    "$ref": "#/components/examples/IMPORT_SCOPE"
                  },
                  "DEMO_LIMITED": {
                    "$ref": "#/components/examples/DEMO_LIMITED"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `IMPORT_CONFLICT`, `IMPORT_RECIPIENT_MISMATCH`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "IMPORT_CONFLICT": {
                    "$ref": "#/components/examples/IMPORT_CONFLICT"
                  },
                  "IMPORT_RECIPIENT_MISMATCH": {
                    "$ref": "#/components/examples/IMPORT_RECIPIENT_MISMATCH"
                  }
                }
              }
            }
          },
          "413": {
            "description": "Request too large: `IMPORT_ROW_LIMIT`, `IMPORT_SIZE_LIMIT`, `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "IMPORT_ROW_LIMIT": {
                    "$ref": "#/components/examples/IMPORT_ROW_LIMIT"
                  },
                  "IMPORT_SIZE_LIMIT": {
                    "$ref": "#/components/examples/IMPORT_SIZE_LIMIT"
                  },
                  "REQUEST_TOO_LARGE": {
                    "$ref": "#/components/examples/REQUEST_TOO_LARGE"
                  }
                }
              }
            }
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/distribution/source-columns": {
      "delete": {
        "operationId": "removeRecipientSourceColumns",
        "tags": ["Gift links"],
        "summary": "Delete retained source columns",
        "description": "Deletes retained columns of one import by their original positions. Recipients, gift history and paid gifts stay. Send the JSON body with `Content-Type: application/json`. Accepts an MCP OAuth token with `gifts:write`.",
        "x-mcp-tool": "remove_recipient_source_columns",
        "x-agent-callable": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "mcpOAuth": ["gifts:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "importId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Stable customer import ID; reuse with identical retry data."
                  },
                  "indices": {
                    "minItems": 1,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 99
                    },
                    "description": "Original source column positions to remove from retained data."
                  }
                },
                "required": ["importId", "indices"],
                "additionalProperties": false
              },
              "examples": {
                "remove": {
                  "summary": "Remove the Owner column",
                  "value": {
                    "importId": "hubspot-export-2026-10-11",
                    "indices": [3]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": SourceImport}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SourceImportResponse"
                },
                "examples": {
                  "removed": {
                    "summary": "No retained columns left",
                    "value": {
                      "data": {
                        "importId": "hubspot-export-2026-10-11",
                        "headers": ["Name", "Email", "Company", "Owner"],
                        "retainedColumnIndices": [],
                        "totalRows": 1,
                        "complete": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `INSUFFICIENT_SCOPE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "COLUMNS_SCOPE": {
                    "$ref": "#/components/examples/COLUMNS_SCOPE"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "SOURCE_IMPORT_NOT_FOUND": {
                    "$ref": "#/components/examples/SOURCE_IMPORT_NOT_FOUND"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict: `IMPORT_INCOMPLETE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "COLUMNS_IMPORT_INCOMPLETE": {
                    "$ref": "#/components/examples/COLUMNS_IMPORT_INCOMPLETE"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/gift-links": {
      "get": {
        "operationId": "listCampaignGiftLinks",
        "tags": ["Gift links"],
        "summary": "List gift-link status",
        "description": "Each address-collection gift link in a campaign: claim `state`, `valueCents`, `paid`, `canRegift`, `canRequestRefund`, refund progress, and the `generation` and `messageVersion` that edits need. `url` appears while a link is usable. Expiry does not refund money. Not paginated.",
        "x-mcp-tool": "list_campaign_gift_links",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [GiftLink]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftLinkListResponse"
                },
                "examples": {
                  "one": {
                    "summary": "One unclaimed link",
                    "value": {
                      "data": [
                        {
                          "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                          "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "recipient": {
                            "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                            "name": "Jamie Chen",
                            "email": "jamie@northstar.example",
                            "company": "Northstar",
                            "sourceSystem": "hubspot",
                            "externalId": "contact-4821",
                            "country": "US",
                            "addressMode": "confirm"
                          },
                          "senderName": "Alex Kim",
                          "senderCompany": "Acme",
                          "contactEmail": "",
                          "logoAssetId": "",
                          "state": "unclaimed",
                          "generation": 1,
                          "landingMessage": "Hi Jamie, a little something from Acme.",
                          "messageVersion": 0,
                          "expiresAt": "2026-10-25T15:04:05.000Z",
                          "url": "https://gtmswag.com/confirm/9f2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d1f",
                          "testMode": true,
                          "paid": true,
                          "refunded": false,
                          "canRegift": true,
                          "valueCents": 3300,
                          "canRequestRefund": false,
                          "email": {
                            "status": "not_sent"
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}/gift-link/message": {
      "post": {
        "operationId": "customizeGiftLinkMessage",
        "tags": ["Gift links"],
        "summary": "Edit one gift link's welcome or sender branding",
        "description": "Changes the welcome shown on one unused link (`{{firstName}}` and `{{company}}` allowed, 500 characters after expansion; empty restores the default) and optionally its sender branding. Send the link's current `generation` and `messageVersion` (as `expectedMessageVersion`); a stale value returns 409 GIFT_LINK_CONFLICT. Does not change the printed note or email anyone.",
        "x-mcp-tool": "customize_gift_link_message",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "generation": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The gift link's current generation."
                  },
                  "expectedMessageVersion": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The gift link's current messageVersion."
                  },
                  "message": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Link welcome message; empty restores default. Not the printed note."
                  },
                  "branding": {
                    "$ref": "#/components/schemas/GiftLinkBranding"
                  }
                },
                "required": ["generation", "expectedMessageVersion"],
                "additionalProperties": false
              },
              "examples": {
                "welcome": {
                  "summary": "A personal welcome",
                  "value": {
                    "generation": 1,
                    "expectedMessageVersion": 0,
                    "message": "Hi {{firstName}}, pick a spot and we'll ship it."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": GiftLink}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftLinkResponse"
                },
                "examples": {
                  "link": {
                    "summary": "The link with its new welcome",
                    "value": {
                      "data": {
                        "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "recipient": {
                          "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                          "name": "Jamie Chen",
                          "email": "jamie@northstar.example",
                          "company": "Northstar",
                          "sourceSystem": "hubspot",
                          "externalId": "contact-4821",
                          "country": "US",
                          "addressMode": "confirm"
                        },
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "contactEmail": "",
                        "logoAssetId": "",
                        "state": "unclaimed",
                        "generation": 1,
                        "landingMessage": "Hi Jamie, pick a spot and we'll ship it.",
                        "messageVersion": 1,
                        "expiresAt": "2026-10-25T15:04:05.000Z",
                        "url": "https://gtmswag.com/confirm/9f2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d1f",
                        "testMode": true,
                        "paid": true,
                        "refunded": false,
                        "canRegift": true,
                        "valueCents": 3300,
                        "canRequestRefund": false,
                        "email": {
                          "status": "not_sent"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestGiftLinkMessage"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenArtwork"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundGiftLink"
          },
          "409": {
            "$ref": "#/components/responses/ConflictGiftLink"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaTypeLogo"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/gift-links/message": {
      "post": {
        "operationId": "customizeCampaignGiftLinks",
        "tags": ["Gift links"],
        "summary": "Edit welcomes or branding on many gift links",
        "description": "Up to 25 unused links of one campaign at once, each with its current `generation` and `expectedMessageVersion`. Omitting `message` keeps each link's own welcome. All-or-nothing. Does not change printed notes or send email.",
        "x-mcp-tool": "customize_campaign_gift_links",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Link welcome message; empty restores default. Not the printed note."
                  },
                  "branding": {
                    "$ref": "#/components/schemas/GiftLinkBranding"
                  },
                  "links": {
                    "minItems": 1,
                    "maxItems": 25,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "generation": {
                          "type": "integer",
                          "exclusiveMinimum": 0,
                          "maximum": 9007199254740991,
                          "description": "The gift link's current generation."
                        },
                        "expectedMessageVersion": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 9007199254740991,
                          "description": "The gift link's current messageVersion."
                        },
                        "sendId": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100,
                          "description": "Send ID (send_): one gift (send), not a campaign.",
                          "pattern": "^send_[A-Za-z0-9_-]+$"
                        }
                      },
                      "required": [
                        "generation",
                        "expectedMessageVersion",
                        "sendId"
                      ],
                      "additionalProperties": false
                    },
                    "description": "Up to 25 links, with current generation/message versions."
                  }
                },
                "required": ["links"],
                "additionalProperties": false
              },
              "examples": {
                "branding": {
                  "summary": "New sender branding on two links",
                  "value": {
                    "branding": {
                      "senderName": "Alex Kim",
                      "senderCompany": "Acme",
                      "contactEmail": "alex@acme.example",
                      "logoAssetId": "asset_9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d"
                    },
                    "links": [
                      {
                        "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "generation": 1,
                        "expectedMessageVersion": 1
                      },
                      {
                        "sendId": "send_7d9f1b3d5f7a9c1e3b5d7f9a1c3e5a7b",
                        "generation": 1,
                        "expectedMessageVersion": 0
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [GiftLink]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftLinkListResponse"
                },
                "examples": {
                  "links": {
                    "summary": "Both links with the new branding",
                    "value": {
                      "data": [
                        {
                          "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                          "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "recipient": {
                            "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                            "name": "Jamie Chen",
                            "email": "jamie@northstar.example",
                            "company": "Northstar",
                            "sourceSystem": "hubspot",
                            "externalId": "contact-4821",
                            "country": "US",
                            "addressMode": "confirm"
                          },
                          "senderName": "Alex Kim",
                          "senderCompany": "Acme",
                          "contactEmail": "alex@acme.example",
                          "logoAssetId": "asset_9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d",
                          "state": "unclaimed",
                          "generation": 1,
                          "landingMessage": "Hi Jamie, a little something from Acme.",
                          "messageVersion": 2,
                          "expiresAt": "2026-10-25T15:04:05.000Z",
                          "url": "https://gtmswag.com/confirm/9f2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d1f",
                          "testMode": true,
                          "paid": true,
                          "refunded": false,
                          "canRegift": true,
                          "valueCents": 3300,
                          "canRequestRefund": false,
                          "email": {
                            "status": "not_sent"
                          }
                        },
                        {
                          "sendId": "send_7d9f1b3d5f7a9c1e3b5d7f9a1c3e5a7b",
                          "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "recipient": {
                            "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                            "name": "Priya Patel",
                            "email": "priya@lumen.example",
                            "company": "Lumen",
                            "country": "US",
                            "addressMode": "confirm"
                          },
                          "senderName": "Alex Kim",
                          "senderCompany": "Acme",
                          "contactEmail": "alex@acme.example",
                          "logoAssetId": "asset_9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d",
                          "state": "unclaimed",
                          "generation": 1,
                          "landingMessage": "Hi Priya, a little something from Acme.",
                          "messageVersion": 1,
                          "expiresAt": "2026-10-25T15:04:05.000Z",
                          "url": "https://gtmswag.com/confirm/9f2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d1f",
                          "testMode": true,
                          "paid": true,
                          "refunded": false,
                          "canRegift": true,
                          "valueCents": 3300,
                          "canRequestRefund": false,
                          "email": {
                            "status": "not_sent"
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestGiftLinkMessage"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenArtwork"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundGiftLink"
          },
          "409": {
            "$ref": "#/components/responses/ConflictGiftLink"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaTypeLogo"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}/gift-link/revoke": {
      "post": {
        "operationId": "revokeGiftLink",
        "tags": ["Gift links"],
        "summary": "Revoke an unused gift link",
        "description": "The link stops working at once. The gift stays reserved (it can be regifted); revoking does not refund it. Redeemed links cannot be revoked. Repeating the call on a revoked link returns it unchanged.",
        "x-mcp-tool": "revoke_gift_link",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "generation": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The gift link's current generation."
                  }
                },
                "required": ["generation"],
                "additionalProperties": false
              },
              "examples": {
                "revoke": {
                  "summary": "Revoke generation 1",
                  "value": {
                    "generation": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": GiftLink}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftLinkResponse"
                },
                "examples": {
                  "revoked": {
                    "summary": "Revoked; no url",
                    "value": {
                      "data": {
                        "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "recipient": {
                          "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                          "name": "Jamie Chen",
                          "email": "jamie@northstar.example",
                          "company": "Northstar",
                          "sourceSystem": "hubspot",
                          "externalId": "contact-4821",
                          "country": "US",
                          "addressMode": "confirm"
                        },
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "contactEmail": "",
                        "logoAssetId": "",
                        "state": "revoked",
                        "generation": 1,
                        "landingMessage": "Hi Jamie, a little something from Acme.",
                        "messageVersion": 0,
                        "expiresAt": "2026-10-25T15:04:05.000Z",
                        "testMode": true,
                        "paid": true,
                        "refunded": false,
                        "canRegift": true,
                        "valueCents": 3300,
                        "canRequestRefund": false,
                        "email": {
                          "status": "not_sent"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundGiftLink"
          },
          "409": {
            "$ref": "#/components/responses/ConflictGiftLink"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}/gift-link/regift": {
      "post": {
        "operationId": "regiftGiftLink",
        "tags": ["Gift links"],
        "summary": "Give an unused gift to someone else",
        "description": "When `canRegift` is true: replaces the recipient, invalidates the old URL and issues a new one (generation + 1, 14 days to claim), keeping payment and gift identity. The new recipient needs `addressMode:\"confirm\"` and a new printed note. No email or charge. After an uncertain response, read the link: its generation and recipient show whether the regift landed.",
        "x-mcp-tool": "regift_gift_link",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "generation": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The gift link's current generation."
                  },
                  "recipient": {
                    "$ref": "#/components/schemas/RecipientInput",
                    "description": "Gift recipient, delivery details and personal note."
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Printed note and recipient fallback."
                  }
                },
                "required": ["generation", "recipient", "message"],
                "additionalProperties": false
              },
              "examples": {
                "regift": {
                  "summary": "Give Jamie's unused gift to Sam",
                  "value": {
                    "generation": 1,
                    "recipient": {
                      "name": "Sam Rivera",
                      "email": "sam@orbit.example",
                      "company": "Orbit",
                      "addressMode": "confirm"
                    },
                    "message": "Sam, a little something from all of us at Acme."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": GiftLink}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftLinkResponse"
                },
                "examples": {
                  "regifted": {
                    "summary": "Generation 2 for the new recipient, with a new link",
                    "value": {
                      "data": {
                        "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "recipient": {
                          "recipientId": "recipient_6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b",
                          "name": "Sam Rivera",
                          "email": "sam@orbit.example",
                          "company": "Orbit",
                          "country": "US",
                          "addressMode": "confirm"
                        },
                        "senderName": "Alex Kim",
                        "senderCompany": "Acme",
                        "contactEmail": "",
                        "logoAssetId": "",
                        "state": "unclaimed",
                        "generation": 2,
                        "landingMessage": "Hi Sam, a little something from Acme.",
                        "messageVersion": 0,
                        "expiresAt": "2026-10-26T10:00:00.000Z",
                        "url": "https://gtmswag.com/confirm/0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f",
                        "testMode": true,
                        "paid": true,
                        "refunded": false,
                        "canRegift": true,
                        "valueCents": 3300,
                        "canRequestRefund": false,
                        "email": {
                          "status": "not_sent"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `INVALID_REQUEST`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "REGIFT_PRIVATE_LINK": {
                    "$ref": "#/components/examples/REGIFT_PRIVATE_LINK"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `RECIPIENT_SCOPE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RECIPIENT_SCOPE": {
                    "$ref": "#/components/examples/RECIPIENT_SCOPE"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundGiftLink"
          },
          "409": {
            "description": "Conflict: `GIFT_LINK_CONFLICT`, `RECIPIENT_IDENTITY_CONFLICT`, `DUPLICATE_RECIPIENT`, `GIFT_RETIRED`, `GIFT_UNAVAILABLE`, `PRICE_QUOTE_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "GIFT_LINK_CONFLICT": {
                    "$ref": "#/components/examples/GIFT_LINK_CONFLICT"
                  },
                  "RECIPIENT_IDENTITY_CONFLICT": {
                    "$ref": "#/components/examples/RECIPIENT_IDENTITY_CONFLICT"
                  },
                  "DUPLICATE_RECIPIENT": {
                    "$ref": "#/components/examples/DUPLICATE_RECIPIENT"
                  },
                  "GIFT_RETIRED": {
                    "$ref": "#/components/examples/GIFT_RETIRED"
                  },
                  "GIFT_UNAVAILABLE": {
                    "$ref": "#/components/examples/GIFT_UNAVAILABLE"
                  },
                  "PRICE_QUOTE_REQUIRED": {
                    "$ref": "#/components/examples/PRICE_QUOTE_REQUIRED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}/gift-link/email": {
      "post": {
        "operationId": "emailGiftLink",
        "tags": ["Gift links"],
        "summary": "Email a gift link (retired)",
        "description": "Retired: always 410 CAPABILITY_RETIRED. Customers send their own outreach; copy the link from `GET /campaigns/{id}/distribution` or export them.",
        "deprecated": true,
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "410": {
            "$ref": "#/components/responses/GoneCapabilityRetired"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/gift-link-settings": {
      "get": {
        "operationId": "getGiftLinkSettings",
        "tags": ["Gift links"],
        "summary": "Read invitation reminder settings (retired)",
        "description": "Invitation reminders are retired: `remindersEnabled` is always false. `version` is kept for older clients.",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": GiftLinkSettings}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftLinkSettingsResponse"
                },
                "examples": {
                  "off": {
                    "summary": "Reminders off",
                    "value": {
                      "data": {
                        "remindersEnabled": false,
                        "version": 0
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "operationId": "updateGiftLinkSettings",
        "tags": ["Gift links"],
        "summary": "Change invitation reminders (retired)",
        "description": "Retired: always 410 CAPABILITY_RETIRED.",
        "deprecated": true,
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Ignored: the route is retired and answers 410 to any well-formed body.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Bad request: `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "410": {
            "$ref": "#/components/responses/GoneCapabilityRetired"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/gift-refunds": {
      "get": {
        "operationId": "listGiftRefunds",
        "tags": ["Gift links"],
        "summary": "List refund requests for unused gifts",
        "description": "Refund requests for a campaign's unused paid gifts, newest first, with `status` `requested`, `processing`, `refunded` or `declined`. Requesting one is a human-only action.",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [GiftRefund]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftRefundListResponse"
                },
                "examples": {
                  "one": {
                    "summary": "One refund in progress",
                    "value": {
                      "data": [
                        {
                          "id": "gref_5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5a",
                          "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                          "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                          "recipientName": "Jamie Chen",
                          "amountCents": 3300,
                          "mode": "test",
                          "status": "processing",
                          "note": "",
                          "createdAt": "2026-10-11T15:04:05.000Z",
                          "updatedAt": "2026-10-11T15:04:05.000Z",
                          "version": 2
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}/gift-link/refund": {
      "post": {
        "operationId": "requestGiftLinkRefund",
        "tags": ["Gift links", "Human only"],
        "summary": "Request a refund for an unused paid gift",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Revokes the link and records the request; repeating it for the same generation returns the same request.",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "generation": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The link's current generation."
                  }
                },
                "required": ["generation"],
                "additionalProperties": false
              },
              "examples": {
                "refund": {
                  "summary": "Refund generation 1",
                  "value": {
                    "generation": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": GiftRefund}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftRefundResponse"
                },
                "examples": {
                  "requested": {
                    "summary": "The refund request",
                    "value": {
                      "data": {
                        "id": "gref_5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5a",
                        "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "recipientName": "Jamie Chen",
                        "amountCents": 3300,
                        "mode": "test",
                        "status": "requested",
                        "note": "",
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "updatedAt": "2026-10-11T15:04:05.000Z",
                        "version": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManagerWorkspace"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundGiftLink"
          },
          "409": {
            "description": "Conflict: `GIFT_LINK_CONFLICT`, `INVALID_REQUEST`, `FUNDING_REFUND_CONFLICT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "REFUND_CONFLICT": {
                    "$ref": "#/components/examples/REFUND_CONFLICT"
                  },
                  "REFUND_UNUSED_ONLY": {
                    "$ref": "#/components/examples/REFUND_UNUSED_ONLY"
                  },
                  "FUNDING_REFUND_CONFLICT": {
                    "$ref": "#/components/examples/FUNDING_REFUND_CONFLICT"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/tracking": {
      "get": {
        "operationId": "getTracking",
        "tags": ["Tracking & events"],
        "summary": "Read gift status",
        "description": "A privacy-minimized, paged snapshot of gift status, links and outcomes, oldest first. Filter by campaign, gift, `externalId` or status. Page with `limit` and `nextCursor` (null on the last page); this cursor is not a change feed (use `GET /events`).",
        "x-mcp-tool": "get_tracking",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "campaignId",
            "in": "query",
            "required": false,
            "description": "Campaign ID (cmp_): a saved campaign or playbook.",
            "schema": {
              "type": "string",
              "maxLength": 100,
              "pattern": "^cmp_[A-Za-z0-9_-]+$"
            },
            "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
          },
          {
            "name": "externalId",
            "in": "query",
            "required": false,
            "description": "External record ID (recipient contact ID).",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "contact-4821"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Delivery status to include.",
            "schema": {
              "type": "string",
              "enum": [
                "awaiting_address",
                "queued",
                "in_production",
                "shipped",
                "delivered",
                "cancelled"
              ]
            },
            "example": "shipped"
          },
          {
            "name": "sendId",
            "in": "query",
            "required": false,
            "description": "Send ID (send_): one gift (send), not a campaign.",
            "schema": {
              "type": "string",
              "maxLength": 100,
              "pattern": "^send_[A-Za-z0-9_-]+$"
            },
            "example": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum records in this page, from 1 to 100.",
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Prior nextCursor for pagination; not a change feed.",
            "schema": {
              "type": "string",
              "maxLength": 2000
            },
            "example": "djE6MTI4NDc="
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": TrackingPage}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackingPageResponse"
                },
                "examples": {
                  "page": {
                    "summary": "One gift, last page",
                    "value": {
                      "data": {
                        "items": [
                          {
                            "id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                            "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                            "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                            "attribution": {},
                            "status": "awaiting_address",
                            "giftLink": {
                              "state": "unclaimed",
                              "generation": 1,
                              "expiresAt": "2026-10-25T15:04:05.000Z"
                            },
                            "orderState": null,
                            "outcome": "none",
                            "mode": "test",
                            "createdAt": "2026-10-11T15:04:05.000Z",
                            "totalCents": 3300,
                            "carrier": null,
                            "trackingNumber": null,
                            "trackingUrl": null
                          }
                        ],
                        "nextCursor": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrCursor"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/tracking": {
      "get": {
        "operationId": "getCampaignTracking",
        "tags": ["Tracking & events"],
        "summary": "Read gift status for one campaign",
        "description": "Same as `GET /tracking` with `campaignId` set from the path.",
        "x-mcp-tool": "get_tracking",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          },
          {
            "name": "externalId",
            "in": "query",
            "required": false,
            "description": "External record ID (recipient contact ID).",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "contact-4821"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Delivery status to include.",
            "schema": {
              "type": "string",
              "enum": [
                "awaiting_address",
                "queued",
                "in_production",
                "shipped",
                "delivered",
                "cancelled"
              ]
            },
            "example": "shipped"
          },
          {
            "name": "sendId",
            "in": "query",
            "required": false,
            "description": "Send ID (send_): one gift (send), not a campaign.",
            "schema": {
              "type": "string",
              "maxLength": 100,
              "pattern": "^send_[A-Za-z0-9_-]+$"
            },
            "example": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum records in this page, from 1 to 100.",
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Prior nextCursor for pagination; not a change feed.",
            "schema": {
              "type": "string",
              "maxLength": 2000
            },
            "example": "djE6MTI4NDc="
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": TrackingPage}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackingPageResponse"
                },
                "examples": {
                  "page": {
                    "summary": "One gift, last page",
                    "value": {
                      "data": {
                        "items": [
                          {
                            "id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                            "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                            "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                            "attribution": {},
                            "status": "awaiting_address",
                            "giftLink": {
                              "state": "unclaimed",
                              "generation": 1,
                              "expiresAt": "2026-10-25T15:04:05.000Z"
                            },
                            "orderState": null,
                            "outcome": "none",
                            "mode": "test",
                            "createdAt": "2026-10-11T15:04:05.000Z",
                            "totalCents": 3300,
                            "carrier": null,
                            "trackingNumber": null,
                            "trackingUrl": null
                          }
                        ],
                        "nextCursor": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrCursor"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}/tracking": {
      "get": {
        "operationId": "getSendTracking",
        "tags": ["Tracking & events"],
        "summary": "Read one gift's tracking",
        "description": "One gift's status, link state, carrier and tracking number (`trackingUrl` only when HTTPS).",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Tracking}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackingResponse"
                },
                "examples": {
                  "one": {
                    "summary": "Awaiting the recipient's address",
                    "value": {
                      "data": {
                        "id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "attribution": {},
                        "status": "awaiting_address",
                        "giftLink": {
                          "state": "unclaimed",
                          "generation": 1,
                          "expiresAt": "2026-10-25T15:04:05.000Z"
                        },
                        "orderState": null,
                        "outcome": "none",
                        "mode": "test",
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "totalCents": 3300,
                        "carrier": null,
                        "trackingNumber": null,
                        "trackingUrl": null
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundSend"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/events": {
      "get": {
        "operationId": "listTrackingEvents",
        "tags": ["Tracking & events"],
        "summary": "Poll tracking events after a cursor",
        "description": "An append-only feed of gift events, oldest first: `send.link_opened` (a recipient opened their gift link), `send.auto_approved` (a playbook's auto-approve rule approved and paid for a gift), status, link, order, tracking and outcome changes. Start without `cursor`, store `nextCursor` after every poll (it is always set) and keep the same filters; `hasMore` says whether to poll again now. Test and live events share the feed: read `mode`. `playbook.person_waiting` is a webhook-only event.",
        "x-mcp-tool": "list_tracking_events",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "campaignId",
            "in": "query",
            "required": false,
            "description": "Campaign ID (cmp_): a saved campaign or playbook.",
            "schema": {
              "type": "string",
              "maxLength": 100,
              "pattern": "^cmp_[A-Za-z0-9_-]+$"
            },
            "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
          },
          {
            "name": "externalId",
            "in": "query",
            "required": false,
            "description": "External record ID (recipient contact ID).",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "contact-4821"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Delivery status to include.",
            "schema": {
              "type": "string",
              "enum": [
                "awaiting_address",
                "queued",
                "in_production",
                "shipped",
                "delivered",
                "cancelled"
              ]
            },
            "example": "shipped"
          },
          {
            "name": "sendId",
            "in": "query",
            "required": false,
            "description": "Send ID (send_): one gift (send), not a campaign.",
            "schema": {
              "type": "string",
              "maxLength": 100,
              "pattern": "^send_[A-Za-z0-9_-]+$"
            },
            "example": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum records in this page, from 1 to 100.",
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Prior event nextCursor; keep filters unchanged when polling.",
            "schema": {
              "type": "string",
              "maxLength": 2000
            },
            "example": "djE6MTI4NDc="
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Tracking event type to include.",
            "schema": {
              "type": "string",
              "enum": [
                "send.created",
                "send.gift_link_changed",
                "send.order_changed",
                "send.address_confirmed",
                "send.link_opened",
                "send.status_changed",
                "send.outcome_reported",
                "send.tracking_changed",
                "send.auto_approved"
              ]
            },
            "example": "send.link_opened"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": TrackingEventsPage}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackingEventsPageResponse"
                },
                "examples": {
                  "page": {
                    "summary": "An auto-approval, then the recipient opened the link",
                    "value": {
                      "data": {
                        "items": [
                          {
                            "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                            "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                            "attribution": {},
                            "mode": "test",
                            "status": "awaiting_address",
                            "outcome": "none",
                            "orderState": null,
                            "carrier": null,
                            "trackingNumber": null,
                            "trackingUrl": null,
                            "id": "1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b",
                            "cursor": "djE6MTI4NDA=",
                            "type": "send.auto_approved",
                            "timestamp": "2026-10-11T15:04:05.000Z"
                          },
                          {
                            "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                            "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                            "attribution": {},
                            "mode": "test",
                            "status": "awaiting_address",
                            "outcome": "none",
                            "orderState": null,
                            "carrier": null,
                            "trackingNumber": null,
                            "trackingUrl": null,
                            "generation": 1,
                            "id": "5e7a9c1b3d5f7a9c1e3b5d7f9a1c3e5b",
                            "cursor": "djE6MTI4NDc=",
                            "type": "send.link_opened",
                            "timestamp": "2026-10-12T09:30:00.000Z"
                          }
                        ],
                        "nextCursor": "djE6MTI4NDc=",
                        "hasMore": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrCursor"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}/outcomes": {
      "post": {
        "operationId": "recordOutcome",
        "tags": ["Tracking & events"],
        "summary": "Record an outcome the customer reported",
        "description": "Only for a reply or meeting the customer explicitly reports; never infer one from delivery or a link open. Deduplicated on `source` + `externalEventId`: the same pair with different details returns 409 IDEMPOTENCY_CONFLICT. Without `externalEventId` every call records a new report.",
        "x-mcp-tool": "record_outcome",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "outcome": {
                    "type": "string",
                    "enum": [
                      "none",
                      "replied",
                      "meeting_booked",
                      "meeting_held"
                    ],
                    "description": "Customer-reported result; never infer from delivery."
                  },
                  "externalEventId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Source event ID for deduplication with the same source."
                  },
                  "source": {
                    "default": "api",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Source for externalEventId deduplication."
                  },
                  "occurredAt": {
                    "type": "string",
                    "format": "date-time",
                    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                    "description": "Outcome time as ISO 8601 with timezone; defaults to now."
                  }
                },
                "required": ["outcome"],
                "additionalProperties": false
              },
              "examples": {
                "meeting": {
                  "summary": "A meeting booked, from the CRM",
                  "value": {
                    "outcome": "meeting_booked",
                    "source": "hubspot",
                    "externalEventId": "meeting-99812",
                    "occurredAt": "2026-10-09T17:00:00-07:00"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Tracking}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackingResponse"
                },
                "examples": {
                  "tracking": {
                    "summary": "The gift with its outcome",
                    "value": {
                      "data": {
                        "id": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "attribution": {},
                        "status": "awaiting_address",
                        "giftLink": {
                          "state": "unclaimed",
                          "generation": 1,
                          "expiresAt": "2026-10-25T15:04:05.000Z"
                        },
                        "orderState": null,
                        "outcome": "meeting_booked",
                        "mode": "test",
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "totalCents": 3300,
                        "carrier": null,
                        "trackingNumber": null,
                        "trackingUrl": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundSend"
          },
          "409": {
            "description": "Conflict: `IDEMPOTENCY_CONFLICT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "OUTCOME_IDEMPOTENCY_CONFLICT": {
                    "$ref": "#/components/examples/OUTCOME_IDEMPOTENCY_CONFLICT"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/results": {
      "get": {
        "operationId": "getCampaignResults",
        "tags": ["Tracking & events"],
        "summary": "Read one campaign's totals",
        "description": "Gifts sent, committed spend and customer-reported meetings for one campaign (test and live combined).",
        "x-mcp-tool": "campaign_results",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": CampaignResults}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignResultsResponse"
                },
                "examples": {
                  "results": {
                    "summary": "Two gifts, one customer-reported meeting",
                    "value": {
                      "data": {
                        "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                        "totalSends": 2,
                        "cancelled": 0,
                        "delivered": 1,
                        "replied": 0,
                        "meetingsHeld": 0,
                        "meetings": 1,
                        "committedCents": 6600,
                        "costPerMeetingCents": 6600,
                        "outcomeSource": "customer_reported",
                        "meetingDenominator": "non-cancelled sends currently marked meeting_booked or meeting_held"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/export": {
      "get": {
        "operationId": "exportCampaignResults",
        "tags": ["Tracking & events"],
        "summary": "Download one campaign's results as CSV",
        "description": "One row per gift: sendId, campaignId, attribution IDs, mode, status, outcome and totalCents.",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file (UTF-8, CRLF line endings).",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment; filename=\"…\"`.",
                "schema": {
                  "type": "string"
                },
                "example": "attachment; filename=\"campaign-results.csv\""
              }
            },
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "csv": {
                    "summary": "One gift",
                    "value": "\"sendId\",\"campaignId\",\"externalId\",\"source\",\"contactId\",\"accountId\",\"opportunityId\",\"mode\",\"status\",\"outcome\",\"totalCents\"\r\n\"send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b\",\"cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e\",\"contact-4821\",\"hubspot\",\"\",\"\",\"\",\"test\",\"awaiting_address\",\"none\",\"3300\"\r\n"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/reports": {
      "get": {
        "operationId": "getReport",
        "tags": ["Tracking & events"],
        "summary": "Read the gifting report",
        "description": "Delivery and value totals across campaigns for one mode (default `test`), filtered by gift creation date (inclusive, UTC), with team-reported replies and meetings. Every campaign appears, even with no gifts.",
        "x-mcp-tool": "get_report",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Inclusive gift creation start date, YYYY-MM-DD in UTC.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
            },
            "example": "2026-10-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Inclusive gift creation end date, YYYY-MM-DD in UTC.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
            },
            "example": "2026-10-31"
          },
          {
            "name": "campaignId",
            "in": "query",
            "required": false,
            "description": "Campaign ID (cmp_): a saved campaign or playbook.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100,
              "pattern": "^cmp_[A-Za-z0-9_-]+$"
            },
            "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "Report test or live gifts separately.",
            "schema": {
              "default": "test",
              "type": "string",
              "enum": ["test", "live"]
            },
            "example": "test"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": GiftingReport}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftingReportResponse"
                },
                "examples": {
                  "october": {
                    "summary": "October, test mode, one campaign",
                    "value": {
                      "data": {
                        "mode": "test",
                        "from": "2026-10-01",
                        "to": "2026-10-31",
                        "totals": {
                          "gifts": 1,
                          "awaitingAddress": 1,
                          "queued": 0,
                          "inProduction": 0,
                          "shipped": 0,
                          "delivered": 0,
                          "cancelled": 0,
                          "committedCents": 3300,
                          "reportedReplies": 0,
                          "reportedMeetings": 0
                        },
                        "campaigns": [
                          {
                            "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                            "name": "New VP of Sales welcome",
                            "status": "active",
                            "gifts": 1,
                            "awaitingAddress": 1,
                            "queued": 0,
                            "inProduction": 0,
                            "shipped": 0,
                            "delivered": 0,
                            "cancelled": 0,
                            "committedCents": 3300,
                            "reportedReplies": 0,
                            "reportedMeetings": 0
                          }
                        ],
                        "outcomeSource": "team_reported"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/reports/export.csv": {
      "get": {
        "operationId": "exportReport",
        "tags": ["Tracking & events"],
        "summary": "Download the gifting report as CSV",
        "description": "The report as CSV, one row per campaign. Same filters as `GET /reports`.",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Inclusive gift creation start date, YYYY-MM-DD in UTC.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
            },
            "example": "2026-10-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Inclusive gift creation end date, YYYY-MM-DD in UTC.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
            },
            "example": "2026-10-31"
          },
          {
            "name": "campaignId",
            "in": "query",
            "required": false,
            "description": "Only this campaign (cmp_).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "Report test or live gifts separately (default test).",
            "schema": {
              "default": "test",
              "type": "string",
              "enum": ["test", "live"]
            },
            "example": "test"
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file (UTF-8, CRLF line endings).",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment; filename=\"…\"`.",
                "schema": {
                  "type": "string"
                },
                "example": "attachment; filename=\"gtm-swag-report.csv\""
              }
            },
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "csv": {
                    "summary": "One campaign (every cell quoted, no trailing newline)",
                    "value": "\"Campaign ID\",\"Campaign\",\"Status\",\"Gifts\",\"Awaiting address\",\"Queued\",\"In production\",\"Shipped\",\"Delivered\",\"Cancelled\",\"Committed USD\",\"Team-reported replies\",\"Team-reported meetings\"\r\n\"cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e\",\"New VP of Sales welcome\",\"active\",\"1\",\"1\",\"0\",\"0\",\"0\",\"0\",\"0\",\"33.00\",\"0\",\"0\""
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "tags": ["Webhooks"],
        "summary": "List webhook endpoints",
        "description": "The workspace's endpoints and the event types each receives. Owner or admin keys only (others get 403 TEAM_MANAGER_REQUIRED). Secrets are never returned again; see the top-level `webhooks` for payloads and signature checks.",
        "x-mcp-tool": "list_webhooks",
        "x-agent-callable": true,
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [Webhook]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookListResponse"
                },
                "examples": {
                  "one": {
                    "summary": "One endpoint for every event",
                    "value": {
                      "data": [
                        {
                          "id": "wh_6c8e0a2b4d6f8a0c2e4b6d8f0a2c4e6b",
                          "url": "https://hooks.acme.example/gtm-swag",
                          "events": ["all"],
                          "createdAt": "2026-10-11T15:04:05.000Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenManager"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "tags": ["Webhooks", "Human only"],
        "summary": "Create a signed webhook endpoint",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. The URL must be public HTTPS on port 443. The response carries the signing `secret` once. Events created before the endpoint are not sent.",
        "x-mcp-tool": "create_webhook",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Public HTTPS destination for signed tracking events."
                  },
                  "events": {
                    "minItems": 1,
                    "maxItems": 10,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "all",
                        "send.created",
                        "send.gift_link_changed",
                        "send.order_changed",
                        "send.address_confirmed",
                        "send.link_opened",
                        "send.status_changed",
                        "send.outcome_reported",
                        "send.tracking_changed",
                        "send.auto_approved",
                        "playbook.person_waiting"
                      ]
                    },
                    "description": "Event types for this webhook, or all."
                  }
                },
                "required": ["url", "events"],
                "additionalProperties": false
              },
              "examples": {
                "waiting": {
                  "summary": "Link opens and people left waiting",
                  "value": {
                    "url": "https://hooks.acme.example/gtm-swag",
                    "events": ["send.link_opened", "playbook.person_waiting"]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success: `{\"data\": WebhookWithSecret}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookWithSecretResponse"
                },
                "examples": {
                  "created": {
                    "summary": "Store the secret now; it is shown once",
                    "value": {
                      "data": {
                        "id": "wh_6c8e0a2b4d6f8a0c2e4b6d8f0a2c4e6b",
                        "url": "https://hooks.acme.example/gtm-swag",
                        "events": [
                          "send.link_opened",
                          "playbook.person_waiting"
                        ],
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "secret": "3b5d7f9a1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `INVALID_REQUEST`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "WEBHOOK_URL": {
                    "$ref": "#/components/examples/WEBHOOK_URL"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `DEMO_LIMITED`, `TEAM_MANAGER_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
                  },
                  "DEMO_LIMITED": {
                    "$ref": "#/components/examples/DEMO_LIMITED"
                  },
                  "TEAM_MANAGER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Unavailable: `WEBHOOK_UNAVAILABLE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "WEBHOOK_UNAVAILABLE": {
                    "$ref": "#/components/examples/WEBHOOK_UNAVAILABLE"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "delete": {
        "operationId": "removeWebhook",
        "tags": ["Webhooks", "Human only"],
        "summary": "Disable a webhook endpoint",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Pending deliveries to it stop.",
        "x-mcp-tool": "remove_webhook",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": OkResult}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResultResponse"
                },
                "examples": {
                  "ok": {
                    "summary": "Disabled",
                    "value": {
                      "data": {
                        "ok": true
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManagerWorkspace"
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "WEBHOOK_NOT_FOUND": {
                    "$ref": "#/components/examples/WEBHOOK_NOT_FOUND"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "tags": ["Webhooks"],
        "summary": "List an endpoint's deliveries, newest first",
        "description": "Delivery attempts for gift events (`source=gift`, default) or playbook events (`source=playbook`), each with `state` `pending`, `sending`, `delivered` or `dead` (after 8 failed attempts). Page with `before` = the previous `nextBefore`. Owner or admin keys only.",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "nextBefore from the previous page; omit for the newest.",
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 9007199254740991
            },
            "example": 412
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Deliveries per page, 1 to 100 (default 50).",
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "example": 50
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "gift for send.* events, playbook for playbook.person_waiting.",
            "schema": {
              "default": "gift",
              "type": "string",
              "enum": ["gift", "playbook"]
            },
            "example": "gift"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": WebhookDeliveriesPage}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveriesPageResponse"
                },
                "examples": {
                  "dead": {
                    "summary": "One dead delivery",
                    "value": {
                      "data": {
                        "items": [
                          {
                            "id": 412,
                            "event_seq": 12847,
                            "type": "send.link_opened",
                            "source": "gift",
                            "state": "dead",
                            "attempts": 8,
                            "next_at": 1791800000000,
                            "last_status": 500,
                            "last_error": "HTTP delivery failed"
                          }
                        ],
                        "nextBefore": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenManager"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries/{deliveryId}/retry": {
      "post": {
        "operationId": "retryWebhookDelivery",
        "tags": ["Webhooks"],
        "summary": "Retry a dead delivery",
        "description": "Starts a new cycle of 8 attempts for a `dead` delivery. Pass `source=playbook` for a playbook event. Owner or admin keys may call it. Send no body; with a workspace key no Content-Type is needed.",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/DeliveryId"
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "Which delivery list the ID belongs to.",
            "schema": {
              "default": "gift",
              "type": "string",
              "enum": ["gift", "playbook"]
            },
            "example": "gift"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": OkResult}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResultResponse"
                },
                "examples": {
                  "ok": {
                    "summary": "Queued again",
                    "value": {
                      "data": {
                        "ok": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenManager"
          },
          "409": {
            "description": "Conflict: `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "DELIVERY_NOT_RETRYABLE": {
                    "$ref": "#/components/examples/DELIVERY_NOT_RETRYABLE"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/artwork": {
      "post": {
        "operationId": "uploadArtwork",
        "tags": ["Artwork"],
        "summary": "Upload a logo, artwork or recipient portrait",
        "description": "Send the raw file bytes (not multipart, not base64) with its `Content-Type` and an `X-Artwork-Filename` whose extension matches; up to 5 MiB. Add `X-Artwork-Purpose: portrait` for a recipient photo (PNG, JPEG or WebP, at least 256 × 256). Use the returned `asset_` ID in `customization.logoAssetId`, `recipient.assetIds` or `recipient.photo`. Artwork has its own rate limits (600 writes a minute) and daily allowances.",
        "x-mcp-tool": "upload_artwork",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "X-Artwork-Filename",
            "in": "header",
            "required": true,
            "description": "Original filename; its extension must match Content-Type (png, jpg/jpeg, webp, pdf).",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9 ._()-]{0,179}$"
            },
            "example": "acme-logo.png"
          },
          {
            "name": "X-Artwork-Purpose",
            "in": "header",
            "required": false,
            "description": "portrait for a recipient photo (PNG, JPEG or WebP, at least 256 × 256); omit for logos and artwork.",
            "schema": {
              "type": "string",
              "enum": ["artwork", "portrait"]
            },
            "example": "portrait"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The raw file bytes, up to 5 MiB.",
          "content": {
            "image/png": {
              "schema": {
                "type": "string",
                "format": "binary"
              },
              "examples": {
                "logo": {
                  "summary": "A PNG logo",
                  "externalValue": "https://gtmswag.com/brand/symbol.png"
                }
              }
            },
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/webp": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "application/pdf": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success: `{\"data\": Asset}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetResponse"
                },
                "examples": {
                  "logo": {
                    "summary": "A PNG logo",
                    "value": {
                      "data": {
                        "id": "asset_9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d",
                        "filename": "acme-logo.png",
                        "mime": "image/png",
                        "bytes": 48211
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `INVALID_REQUEST`, `PORTRAIT_RESOLUTION`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "ARTWORK_EMPTY": {
                    "$ref": "#/components/examples/ARTWORK_EMPTY"
                  },
                  "PORTRAIT_RESOLUTION": {
                    "$ref": "#/components/examples/PORTRAIT_RESOLUTION"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenDemo"
          },
          "413": {
            "description": "Request too large: `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "ARTWORK_TOO_LARGE": {
                    "$ref": "#/components/examples/ARTWORK_TOO_LARGE"
                  }
                }
              }
            }
          },
          "415": {
            "description": "Unsupported media type: `ARTWORK_TYPE`, `ARTWORK_SIGNATURE`, `PORTRAIT_IMAGE_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "ARTWORK_TYPE": {
                    "$ref": "#/components/examples/ARTWORK_TYPE"
                  },
                  "ARTWORK_SIGNATURE": {
                    "$ref": "#/components/examples/ARTWORK_SIGNATURE"
                  },
                  "PORTRAIT_IMAGE_REQUIRED": {
                    "$ref": "#/components/examples/PORTRAIT_IMAGE_REQUIRED"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsArtwork"
          },
          "503": {
            "description": "Unavailable: `ARTWORK_NOT_READY`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "ARTWORK_NOT_READY": {
                    "$ref": "#/components/examples/ARTWORK_NOT_READY"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/artwork/{id}": {
      "get": {
        "operationId": "getArtwork",
        "tags": ["Artwork"],
        "summary": "Download an uploaded file",
        "description": "The stored file with its media type, as an attachment; `preview=1` returns images inline.",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/AssetId"
          },
          {
            "name": "preview",
            "in": "query",
            "required": false,
            "description": "1 shows an image inline instead of as a download.",
            "schema": {
              "type": "string",
              "const": "1"
            },
            "example": "1"
          }
        ],
        "responses": {
          "200": {
            "description": "The stored file with its own media type, as an attachment (or inline with `preview=1`).",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment; filename=\"…\"`, or `inline; filename=\"…\"` with `preview=1`.",
                "schema": {
                  "type": "string"
                },
                "example": "attachment; filename=\"acme-logo.png\""
              }
            },
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                },
                "examples": {
                  "logo": {
                    "summary": "A PNG logo",
                    "externalValue": "https://gtmswag.com/brand/symbol.png"
                  }
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "ARTWORK_NOT_FOUND": {
                    "$ref": "#/components/examples/ARTWORK_NOT_FOUND"
                  }
                }
              }
            }
          },
          "415": {
            "description": "Unsupported media type: `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "PREVIEW_IMAGES_ONLY": {
                    "$ref": "#/components/examples/PREVIEW_IMAGES_ONLY"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/ArtworkRateLimited"
          },
          "503": {
            "description": "Unavailable: `ARTWORK_NOT_READY`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "ARTWORK_NOT_READY": {
                    "$ref": "#/components/examples/ARTWORK_NOT_READY_WORKSPACE_READ"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/artwork/import-photo": {
      "post": {
        "operationId": "importRecipientPhoto",
        "tags": ["Artwork"],
        "summary": "Import a recipient photo from a public URL",
        "description": "Fetches a direct public HTTPS image (PNG, JPEG or WebP, up to 5 MiB) the customer supplied with explicit permission to use it (`rightsConfirmed:true`), and returns a private portrait asset for `recipient.photo`. Profile pages such as LinkedIn cannot be imported; use `photo:{source:\"linkedin\"}` for staff sourcing.",
        "x-mcp-tool": "import_recipient_photo",
        "x-agent-callable": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 2048,
                    "format": "uri",
                    "description": "Direct public HTTPS PNG/JPEG/WebP URL, up to 5 MiB."
                  },
                  "rightsConfirmed": {
                    "type": "boolean",
                    "const": true,
                    "description": "True only with explicit photo-use permission."
                  }
                },
                "required": ["url", "rightsConfirmed"],
                "additionalProperties": false
              },
              "examples": {
                "photo": {
                  "summary": "A headshot the customer supplied",
                  "value": {
                    "url": "https://cdn.northstar.example/team/jamie-chen.jpg",
                    "rightsConfirmed": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success: `{\"data\": Asset}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetResponse"
                },
                "examples": {
                  "asset": {
                    "summary": "The private portrait asset",
                    "value": {
                      "data": {
                        "id": "asset_9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d",
                        "filename": "recipient-photo.jpg",
                        "mime": "image/jpeg",
                        "bytes": 182340
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `PHOTO_URL`, `PHOTO_DOWNLOAD`, `PORTRAIT_RESOLUTION`, `INVALID_JSON`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "PHOTO_URL": {
                    "$ref": "#/components/examples/PHOTO_URL"
                  },
                  "PHOTO_DOWNLOAD": {
                    "$ref": "#/components/examples/PHOTO_DOWNLOAD"
                  },
                  "PORTRAIT_RESOLUTION": {
                    "$ref": "#/components/examples/PORTRAIT_RESOLUTION"
                  },
                  "INVALID_JSON": {
                    "$ref": "#/components/examples/INVALID_JSON"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenDemo"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "description": "Unsupported media type: `PHOTO_TYPE`, `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "PHOTO_TYPE": {
                    "$ref": "#/components/examples/PHOTO_TYPE"
                  },
                  "JSON_REQUIRED": {
                    "$ref": "#/components/examples/JSON_REQUIRED"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsArtwork"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/billing/config": {
      "get": {
        "operationId": "getBillingConfig",
        "tags": ["Billing"],
        "summary": "Read checkout availability",
        "description": "Whether campaign checkout is available in this workspace (`mode` `sandbox`, `live` or `disabled`). `canPay` is true only for a signed-in owner or admin; keys always get false.",
        "x-mcp-tool": "get_billing_config",
        "x-agent-callable": true,
        "responses": {
          "200": {
            "description": "Success: `{\"data\": BillingConfig}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingConfigResponse"
                },
                "examples": {
                  "key": {
                    "summary": "Read with a key",
                    "value": {
                      "data": {
                        "enabled": true,
                        "mode": "sandbox",
                        "canPay": false
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/billing/checkouts": {
      "get": {
        "operationId": "listCampaignCheckouts",
        "tags": ["Billing"],
        "summary": "List campaign payments and invoices",
        "description": "Campaign checkouts, newest first, with state, amounts and Stripe invoice links. Owner or admin keys only. Page by passing the last item's `cursor` as `before`.",
        "x-mcp-tool": "list_invoices",
        "x-agent-callable": true,
        "parameters": [
          {
            "name": "campaignId",
            "in": "query",
            "required": false,
            "description": "Only this campaign (cmp_).",
            "schema": {
              "type": "string",
              "maxLength": 100,
              "pattern": "^cmp_[A-Za-z0-9_-]+$"
            },
            "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Checkouts per page, 1 to 100 (default 50).",
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "example": 50
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "The last item's cursor from the previous page.",
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "example": "2026-10-11T15:04:05.000Z|cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [Checkout]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutListResponse"
                },
                "examples": {
                  "one": {
                    "summary": "One open checkout",
                    "value": {
                      "data": [
                        {
                          "id": "cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b",
                          "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                          "state": "open",
                          "amountCents": 5000,
                          "recipientCount": 1,
                          "remainingCount": 1,
                          "launchCursor": null,
                          "currency": "usd",
                          "mode": "sandbox",
                          "policyVersion": 2,
                          "createdAt": "2026-10-11T15:04:05.000Z",
                          "cursor": "2026-10-11T15:04:05.000Z|cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b",
                          "expiresAt": "2026-10-11T16:04:05.000Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request: `VALIDATION_ERROR`, `INVALID_REQUEST`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
                  },
                  "INVALID_BILLING_CURSOR": {
                    "$ref": "#/components/examples/INVALID_BILLING_CURSOR"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenManager"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/billing/checkouts/{id}/items": {
      "get": {
        "operationId": "listCheckoutItems",
        "tags": ["Billing"],
        "summary": "List the gifts a live checkout paid for",
        "description": "Each recipient a live prepaid checkout funded, with its gift, state and whether a refund can be requested. Owner or admin keys only; sandbox checkouts return 404.",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CheckoutId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [CheckoutItem]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutItemListResponse"
                },
                "examples": {
                  "one": {
                    "summary": "One prepaid gift, still unused",
                    "value": {
                      "data": [
                        {
                          "recipientId": "recipient_3e5a7c9b1d3f5a7c9e1b3d5f7a9c1e3b",
                          "recipientName": "Priya Patel",
                          "amountCents": 5000,
                          "sendId": "send_7d9f1b3d5f7a9c1e3b5d7f9a1c3e5a7b",
                          "state": "awaiting_address",
                          "canRequestRefund": true
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenManager"
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "FUNDED_CHECKOUT_NOT_FOUND": {
                    "$ref": "#/components/examples/FUNDED_CHECKOUT_NOT_FOUND"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/billing/checkouts/{id}/reconcile": {
      "post": {
        "operationId": "reconcileCampaignCheckout",
        "tags": ["Billing"],
        "summary": "Check a checkout's payment with Stripe",
        "description": "Verifies an uncertain checkout directly with Stripe and returns its state and invoice links. Owner or admin keys may call it. Send no body; with a workspace key no Content-Type is needed.",
        "x-mcp-tool": "reconcile_campaign_checkout",
        "x-agent-callable": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/CheckoutId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Checkout}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                },
                "examples": {
                  "paid": {
                    "summary": "Paid",
                    "value": {
                      "data": {
                        "id": "cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                        "state": "paid",
                        "amountCents": 5000,
                        "recipientCount": 1,
                        "remainingCount": 1,
                        "launchCursor": null,
                        "currency": "usd",
                        "mode": "sandbox",
                        "policyVersion": 2,
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "cursor": "2026-10-11T15:04:05.000Z|cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b",
                        "expiresAt": "2026-10-11T16:04:05.000Z",
                        "paidAt": "2026-10-11T15:04:05.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenManager"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCheckout"
          },
          "409": {
            "description": "Conflict: `STRIPE_EVIDENCE_INVALID`, `BILLING_RECOVERY_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "STRIPE_EVIDENCE_INVALID": {
                    "$ref": "#/components/examples/STRIPE_EVIDENCE_INVALID"
                  },
                  "BILLING_RECOVERY_REQUIRED": {
                    "$ref": "#/components/examples/BILLING_RECOVERY_REQUIRED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/UnavailableStripe"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/billing/checkouts/{id}/cancel": {
      "post": {
        "operationId": "cancelCampaignCheckout",
        "tags": ["Billing", "Human only"],
        "summary": "Cancel an unpaid checkout",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Expires an unpaid checkout so the campaign can be edited again; paid checkouts refuse with 409 CHECKOUT_ALREADY_PAID.",
        "x-mcp-tool": "cancel_campaign_checkout",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CheckoutId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": Checkout}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                },
                "examples": {
                  "cancelled": {
                    "summary": "Cancelled; the campaign can be edited again",
                    "value": {
                      "data": {
                        "id": "cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                        "state": "cancelled",
                        "amountCents": 5000,
                        "recipientCount": 1,
                        "remainingCount": 1,
                        "launchCursor": null,
                        "currency": "usd",
                        "mode": "sandbox",
                        "policyVersion": 2,
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "cursor": "2026-10-11T15:04:05.000Z|cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b",
                        "expiresAt": "2026-10-11T16:04:05.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManagerWorkspace"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCheckout"
          },
          "409": {
            "description": "Conflict: `CHECKOUT_ALREADY_PAID`, `STRIPE_EVIDENCE_INVALID`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "CHECKOUT_ALREADY_PAID": {
                    "$ref": "#/components/examples/CHECKOUT_ALREADY_PAID"
                  },
                  "STRIPE_EVIDENCE_INVALID": {
                    "$ref": "#/components/examples/STRIPE_EVIDENCE_INVALID"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/UnavailableStripe"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaigns/{id}/checkout": {
      "post": {
        "operationId": "createCampaignCheckout",
        "tags": ["Billing", "Human only"],
        "summary": "Start checkout for a reviewed batch campaign",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Hand the campaign review URL to them. Starts a Stripe checkout for the reviewed people without a gift; playbooks are paid from the balance instead (409 ALWAYS_ON_BALANCE_FUNDED).",
        "x-mcp-tool": "create_campaign_checkout",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CampaignId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "expectedPolicyVersion": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The campaign's current policyVersion; a stale value returns POLICY_CHANGED."
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 150,
                    "description": "Same key for identical retries only."
                  }
                },
                "required": ["expectedPolicyVersion", "idempotencyKey"],
                "additionalProperties": false
              },
              "examples": {
                "checkout": {
                  "summary": "Pay for the reviewed people (signed-in owner or admin)",
                  "value": {
                    "expectedPolicyVersion": 2,
                    "idempotencyKey": "q4-champions-checkout-1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success: `{\"data\": Checkout}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                },
                "examples": {
                  "open": {
                    "summary": "An open Stripe checkout",
                    "value": {
                      "data": {
                        "id": "cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b",
                        "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                        "state": "open",
                        "amountCents": 5000,
                        "recipientCount": 1,
                        "remainingCount": 1,
                        "launchCursor": null,
                        "currency": "usd",
                        "mode": "sandbox",
                        "policyVersion": 2,
                        "createdAt": "2026-10-11T15:04:05.000Z",
                        "cursor": "2026-10-11T15:04:05.000Z|cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b",
                        "expiresAt": "2026-10-11T16:04:05.000Z",
                        "url": "https://checkout.stripe.com/c/pay/cs_test_b1C2d3E4f5G6"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManager"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundCampaign"
          },
          "409": {
            "description": "Conflict: `ALWAYS_ON_BALANCE_FUNDED`, `IDEMPOTENCY_CONFLICT`, `BUDGET_EXCEEDED`, `COUNT_EXCEEDED`, `REPEAT_REVIEW_REQUIRED`, `POLICY_CHANGED`, `CAMPAIGN_INACTIVE`, `NO_NEW_RECIPIENTS`, `CHECKOUT_LOCKED`, `GIFT_RETIRED`, `GIFT_UNAVAILABLE`, `PRICE_QUOTE_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "ALWAYS_ON_BALANCE_FUNDED": {
                    "$ref": "#/components/examples/ALWAYS_ON_BALANCE_FUNDED"
                  },
                  "CHECKOUT_IDEMPOTENCY_CONFLICT": {
                    "$ref": "#/components/examples/CHECKOUT_IDEMPOTENCY_CONFLICT"
                  },
                  "BUDGET_EXCEEDED": {
                    "$ref": "#/components/examples/BUDGET_EXCEEDED"
                  },
                  "CHECKOUT_COUNT_EXCEEDED": {
                    "$ref": "#/components/examples/CHECKOUT_COUNT_EXCEEDED"
                  },
                  "REPEAT_REVIEW_CHECKOUT": {
                    "$ref": "#/components/examples/REPEAT_REVIEW_CHECKOUT"
                  },
                  "CHECKOUT_POLICY_CHANGED": {
                    "$ref": "#/components/examples/CHECKOUT_POLICY_CHANGED"
                  },
                  "CAMPAIGN_INACTIVE_CHECKOUT": {
                    "$ref": "#/components/examples/CAMPAIGN_INACTIVE_CHECKOUT"
                  },
                  "NO_NEW_RECIPIENTS": {
                    "$ref": "#/components/examples/NO_NEW_RECIPIENTS"
                  },
                  "CHECKOUT_LOCKED_BUY": {
                    "$ref": "#/components/examples/CHECKOUT_LOCKED_BUY"
                  },
                  "GIFT_RETIRED": {
                    "$ref": "#/components/examples/GIFT_RETIRED"
                  },
                  "GIFT_UNAVAILABLE": {
                    "$ref": "#/components/examples/GIFT_UNAVAILABLE"
                  },
                  "PRICE_QUOTE_REQUIRED": {
                    "$ref": "#/components/examples/PRICE_QUOTE_REQUIRED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Unavailable: `SANDBOX_CHECKOUT_DISABLED`, `PREPAID_DISABLED`, `STRIPE_UNAVAILABLE`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "SANDBOX_CHECKOUT_DISABLED": {
                    "$ref": "#/components/examples/SANDBOX_CHECKOUT_DISABLED"
                  },
                  "PREPAID_DISABLED": {
                    "$ref": "#/components/examples/PREPAID_DISABLED"
                  },
                  "STRIPE_UNAVAILABLE": {
                    "$ref": "#/components/examples/STRIPE_UNAVAILABLE"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/campaign-checkouts/{id}/items/{recipientId}/refund": {
      "post": {
        "operationId": "requestFundingRefund",
        "tags": ["Billing", "Human only"],
        "summary": "Request a refund for one prepaid gift",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. For a live prepaid checkout item that is still unused; send the checkout's current `financialRevision` as `expectedRevision`. Repeating it returns the same request.",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CheckoutId"
          },
          {
            "$ref": "#/components/parameters/RecipientId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "expectedRevision": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 9007199254740991,
                    "description": "The checkout's current financialRevision."
                  }
                },
                "required": ["expectedRevision"],
                "additionalProperties": false
              },
              "examples": {
                "refund": {
                  "summary": "Refund one unused gift",
                  "value": {
                    "expectedRevision": 3
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": FundingRefundRequest}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FundingRefundRequestResponse"
                },
                "examples": {
                  "requested": {
                    "summary": "The refund request",
                    "value": {
                      "data": {
                        "id": "cfr_9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenHumanOnlyOrManagerWorkspace"
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "ALLOCATION_NOT_FOUND": {
                    "$ref": "#/components/examples/ALLOCATION_NOT_FOUND"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict: `FUNDING_REFUND_CONFLICT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "FUNDING_REFUND_CONFLICT": {
                    "$ref": "#/components/examples/FUNDING_REFUND_CONFLICT"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/checkout": {
      "get": {
        "operationId": "listGiftCheckouts",
        "tags": ["Billing", "Human only"],
        "summary": "List open payment checkouts for reviewed live gifts",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Live workspaces only. Supply exactly one of `sendId` or `campaignId`.",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "sendId",
            "in": "query",
            "required": false,
            "description": "A gift (send_).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "example": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b"
          },
          {
            "name": "campaignId",
            "in": "query",
            "required": false,
            "description": "A campaign (cmp_).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": GiftCheckoutList}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftCheckoutListResponse"
                },
                "examples": {
                  "open": {
                    "summary": "One open checkout for a reviewed gift",
                    "value": {
                      "data": {
                        "items": [
                          {
                            "id": "pay_2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c",
                            "state": "open",
                            "url": "https://checkout.stripe.com/c/pay/cs_test_b1C2d3E4f5G6",
                            "expiresAt": 1791800645,
                            "totalCents": 7400,
                            "idempotencyKey": "live-gifts-2026-10-11",
                            "sendIds": ["send_7d9f1b3d5f7a9c1e3b5d7f9a1c3e5a7b"]
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`, `LIVE_NOT_READY`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE_READ"
                  },
                  "TEAM_MANAGER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
                  },
                  "LIVE_NOT_READY": {
                    "$ref": "#/components/examples/LIVE_NOT_READY"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createGiftCheckout",
        "tags": ["Billing", "Human only"],
        "summary": "Pay for reviewed live gifts",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Live workspaces only: one Stripe checkout for up to 100 reviewed gifts awaiting payment. Gifts already paid from the balance refuse with 409 BALANCE_FUNDED.",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sendIds": {
                    "minItems": 1,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 100
                    },
                    "description": "Reviewed gifts awaiting payment (send_), each once."
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 150,
                    "description": "Same key for identical retries only."
                  }
                },
                "required": ["sendIds", "idempotencyKey"],
                "additionalProperties": false
              },
              "examples": {
                "pay": {
                  "summary": "Pay for one reviewed live gift",
                  "value": {
                    "sendIds": ["send_7d9f1b3d5f7a9c1e3b5d7f9a1c3e5a7b"],
                    "idempotencyKey": "live-gifts-2026-10-11"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": GiftCheckout}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftCheckoutResponse"
                },
                "examples": {
                  "open": {
                    "summary": "An open Stripe checkout",
                    "value": {
                      "data": {
                        "id": "pay_2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c",
                        "state": "open",
                        "url": "https://checkout.stripe.com/c/pay/cs_test_b1C2d3E4f5G6",
                        "expiresAt": 1791800645,
                        "totalCents": 7400
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenLiveCheckout"
          },
          "409": {
            "$ref": "#/components/responses/ConflictGiftCheckout"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/UnavailableStripe"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sends/{id}/checkout": {
      "post": {
        "operationId": "createSendCheckout",
        "tags": ["Billing", "Human only"],
        "summary": "Pay for one reviewed live gift",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Same as `POST /checkout` for one gift. A gift paid from the balance refuses with 409 BALANCE_FUNDED. The body is validated first, so a key with an invalid body gets 400 before 403.",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SendId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "idempotencyKey": {
                    "type": "string",
                    "description": "Same key for identical retries only (8 to 150 characters)."
                  }
                },
                "required": ["idempotencyKey"],
                "additionalProperties": false
              },
              "examples": {
                "pay": {
                  "summary": "Pay for this gift",
                  "value": {
                    "idempotencyKey": "live-gift-priya-patel-1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": GiftCheckout}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GiftCheckoutResponse"
                },
                "examples": {
                  "open": {
                    "summary": "An open Stripe checkout",
                    "value": {
                      "data": {
                        "id": "pay_2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c",
                        "state": "open",
                        "url": "https://checkout.stripe.com/c/pay/cs_test_b1C2d3E4f5G6",
                        "expiresAt": 1791800645,
                        "totalCents": 7400
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenLiveCheckout"
          },
          "409": {
            "$ref": "#/components/responses/ConflictGiftCheckout"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/UnavailableStripe"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/settings": {
      "get": {
        "operationId": "getWorkspaceSettings",
        "tags": ["Team & settings"],
        "summary": "Read workspace defaults",
        "description": "The default sender name, company, meeting URL, website and brand color new campaigns use.",
        "x-mcp-tool": "get_workspace_settings",
        "x-agent-callable": true,
        "responses": {
          "200": {
            "description": "Success: `{\"data\": WorkspaceSettings}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceSettingsResponse"
                },
                "examples": {
                  "settings": {
                    "summary": "Workspace defaults",
                    "value": {
                      "data": {
                        "company": "Acme",
                        "name": "Alex Kim",
                        "meetingUrl": "https://cal.acme.example/alex",
                        "website": "https://acme.example",
                        "brandColor": "#2454FF",
                        "webhookUrl": ""
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "operationId": "updateWorkspaceSettings",
        "tags": ["Team & settings"],
        "summary": "Update workspace defaults",
        "description": "Updates only the supplied fields. Owner or admin keys may call it (others get 403 TEAM_MANAGER_REQUIRED). Does not change account identity, payment or team membership.",
        "x-mcp-tool": "update_workspace_settings",
        "x-agent-callable": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "company": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Default workspace sender company."
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Default workspace sender name."
                  },
                  "meetingUrl": {
                    "$ref": "#/components/schemas/UrlOrEmpty",
                    "description": "Optional meeting URL; empty string clears it."
                  },
                  "website": {
                    "$ref": "#/components/schemas/UrlOrEmpty",
                    "description": "Workspace website URL; empty string clears it."
                  },
                  "brandColor": {
                    "type": "string",
                    "pattern": "^#[0-9a-fA-F]{6}$",
                    "description": "Six-digit hex brand color, e.g. #2454FF."
                  },
                  "webhookUrl": {
                    "$ref": "#/components/schemas/UrlOrEmpty",
                    "description": "Default webhook URL; empty string clears it."
                  }
                },
                "additionalProperties": false
              },
              "examples": {
                "brand": {
                  "summary": "New brand color and meeting link",
                  "value": {
                    "brandColor": "#0F766E",
                    "meetingUrl": "https://cal.acme.example/alex-30"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": WorkspaceSettings}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceSettingsResponse"
                },
                "examples": {
                  "settings": {
                    "summary": "The saved defaults",
                    "value": {
                      "data": {
                        "company": "Acme",
                        "name": "Alex Kim",
                        "meetingUrl": "https://cal.acme.example/alex-30",
                        "website": "https://acme.example",
                        "brandColor": "#0F766E",
                        "webhookUrl": ""
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenManager"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/team/members": {
      "get": {
        "operationId": "listTeamMembers",
        "tags": ["Team & settings"],
        "summary": "List team members",
        "description": "Members and roles, owner first.",
        "x-mcp-tool": "list_team_members",
        "x-agent-callable": true,
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [TeamMember]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamMemberListResponse"
                },
                "examples": {
                  "team": {
                    "summary": "Owner and one member",
                    "value": {
                      "data": [
                        {
                          "userId": "usr_2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b",
                          "email": "alex@acme.example",
                          "name": "Alex Kim",
                          "role": "owner",
                          "joinedAt": "2026-09-01T10:00:00.000Z"
                        },
                        {
                          "userId": "usr_5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d",
                          "email": "dana@acme.example",
                          "name": "Dana Lee",
                          "role": "member",
                          "joinedAt": "2026-09-15T10:00:00.000Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/team/invitations": {
      "get": {
        "operationId": "listTeamInvitations",
        "tags": ["Team & settings"],
        "summary": "List team invitations",
        "description": "The latest 100 invitations, newest first. Owner or admin keys only.",
        "x-mcp-tool": "list_team_invitations",
        "x-agent-callable": true,
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [TeamInvitation]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamInvitationListResponse"
                },
                "examples": {
                  "pending": {
                    "summary": "One pending invitation",
                    "value": {
                      "data": [
                        {
                          "id": "inv_8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e",
                          "email": "sam@acme.example",
                          "role": "member",
                          "invitedBy": "usr_2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b",
                          "createdAt": "2026-10-11T15:04:05.000Z",
                          "expiresAt": "2026-10-18T15:04:05.000Z",
                          "status": "pending"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenManager"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "inviteTeamMember",
        "tags": ["Team & settings", "Human only"],
        "summary": "Invite a teammate",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Only the owner may invite admins. Returns a private `inviteUrl` (valid 7 days).",
        "x-mcp-tool": "invite_team_member",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
                    "description": "Recipient or teammate email address."
                  },
                  "role": {
                    "type": "string",
                    "enum": ["admin", "member"],
                    "description": "Workspace role; only owners may grant admin access."
                  }
                },
                "required": ["email", "role"],
                "additionalProperties": false
              },
              "examples": {
                "member": {
                  "summary": "Invite a member",
                  "value": {
                    "email": "sam@acme.example",
                    "role": "member"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success: `{\"data\": TeamInvitationCreated}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamInvitationCreatedResponse"
                },
                "examples": {
                  "invited": {
                    "summary": "The invitation and its private URL",
                    "value": {
                      "data": {
                        "invitation": {
                          "id": "inv_8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e",
                          "email": "sam@acme.example",
                          "role": "member",
                          "invitedBy": "usr_2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b",
                          "createdAt": "2026-10-11T15:04:05.000Z",
                          "expiresAt": "2026-10-18T15:04:05.000Z",
                          "status": "pending"
                        },
                        "inviteUrl": "https://gtmswag.com/join-team?token=6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b",
                        "emailQueued": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`, `ACCOUNT_REQUIRED`, `TEAM_OWNER_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
                  },
                  "TEAM_MANAGER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
                  },
                  "ACCOUNT_REQUIRED": {
                    "$ref": "#/components/examples/ACCOUNT_REQUIRED"
                  },
                  "TEAM_OWNER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_OWNER_REQUIRED"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict: `ALREADY_MEMBER`, `TEAM_CHANGED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "ALREADY_MEMBER": {
                    "$ref": "#/components/examples/ALREADY_MEMBER"
                  },
                  "TEAM_CHANGED": {
                    "$ref": "#/components/examples/TEAM_CHANGED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "description": "Too many requests: `RATE_LIMIT`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "INVITE_RATE_LIMIT": {
                    "$ref": "#/components/examples/INVITE_RATE_LIMIT"
                  },
                  "RATE_LIMIT": {
                    "$ref": "#/components/examples/RATE_LIMIT"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/team/invitations/{id}": {
      "delete": {
        "operationId": "revokeTeamInvitation",
        "tags": ["Team & settings", "Human only"],
        "summary": "Revoke an unused invitation",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Revoking an admin invitation needs the owner.",
        "x-mcp-tool": "revoke_team_invitation",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/InvitationId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": OkResult}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResultResponse"
                },
                "examples": {
                  "ok": {
                    "summary": "Done",
                    "value": {
                      "data": {
                        "ok": true
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`, `TEAM_OWNER_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
                  },
                  "TEAM_MANAGER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
                  },
                  "TEAM_OWNER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_OWNER_REQUIRED"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found: `NOT_FOUND`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "INVITATION_NOT_FOUND": {
                    "$ref": "#/components/examples/INVITATION_NOT_FOUND"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict: `INVITATION_CLOSED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "INVITATION_CLOSED": {
                    "$ref": "#/components/examples/INVITATION_CLOSED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/team/members/{id}": {
      "patch": {
        "operationId": "updateTeamMember",
        "tags": ["Team & settings", "Human only"],
        "summary": "Change a teammate's role",
        "description": "Human only: The signed-in workspace owner does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Demoting someone to member turns off the auto-approve rules they turned on.",
        "x-mcp-tool": "update_team_member",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/MemberId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": ["admin", "member"],
                    "description": "Workspace role; only owners may grant admin access."
                  }
                },
                "required": ["role"],
                "additionalProperties": false
              },
              "examples": {
                "admin": {
                  "summary": "Make Dana an admin",
                  "value": {
                    "role": "admin"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success: `{\"data\": TeamMember}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamMemberResponse"
                },
                "examples": {
                  "admin": {
                    "summary": "The teammate with the new role",
                    "value": {
                      "data": {
                        "userId": "usr_5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d",
                        "email": "dana@acme.example",
                        "name": "Dana Lee",
                        "role": "admin",
                        "joinedAt": "2026-09-15T10:00:00.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestValidationOrJson"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`, `OWNER_REQUIRED`, `TEAM_OWNER_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
                  },
                  "TEAM_MANAGER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
                  },
                  "OWNER_ROLE_FIXED": {
                    "$ref": "#/components/examples/OWNER_ROLE_FIXED"
                  },
                  "TEAM_OWNER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_OWNER_REQUIRED"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundMember"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "removeTeamMember",
        "tags": ["Team & settings", "Human only"],
        "summary": "Remove a teammate",
        "description": "Human only: A signed-in owner or admin does this in the browser at gtmswag.com. API keys and OAuth connections receive 403 HUMAN_APPROVAL_REQUIRED with a `url` to hand to that person. Removing an admin needs the owner. The member's keys for this workspace are revoked and their auto-approve rules turned off.",
        "x-mcp-tool": "remove_team_member",
        "x-human-only": true,
        "x-agent-callable": false,
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/MemberId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success: `{\"data\": OkResult}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResultResponse"
                },
                "examples": {
                  "ok": {
                    "summary": "Done",
                    "value": {
                      "data": {
                        "ok": true
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`, `OWNER_REQUIRED`, `TEAM_OWNER_REQUIRED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "HUMAN_APPROVAL_REQUIRED": {
                    "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
                  },
                  "TEAM_MANAGER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
                  },
                  "OWNER_REQUIRED": {
                    "$ref": "#/components/examples/OWNER_REQUIRED"
                  },
                  "TEAM_OWNER_REQUIRED": {
                    "$ref": "#/components/examples/TEAM_OWNER_REQUIRED"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundMember"
          },
          "409": {
            "description": "Conflict: `TEAM_CHANGED`. Each example says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "TEAM_CHANGED": {
                    "$ref": "#/components/examples/TEAM_CHANGED"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/JsonRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/workspaces": {
      "get": {
        "operationId": "listWorkspaces",
        "tags": ["Team & settings"],
        "summary": "List the key's workspace",
        "description": "A key belongs to one workspace, so this returns just that one (a signed-in person sees every workspace they belong to).",
        "x-agent-callable": true,
        "responses": {
          "200": {
            "description": "Success: `{\"data\": [Workspace]}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceListResponse"
                },
                "examples": {
                  "key": {
                    "summary": "The key's workspace",
                    "value": {
                      "data": [
                        {
                          "teamId": "team_7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a",
                          "company": "Acme",
                          "role": "admin",
                          "isDemo": false,
                          "active": true
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "webhooks": {
    "send.created": {
      "post": {
        "operationId": "sendCreatedWebhook",
        "tags": ["Webhooks"],
        "summary": "A gift was created",
        "description": "Sent to endpoints subscribed to `send.created` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendCreatedEvent"
              },
              "examples": {
                "sendCreated": {
                  "summary": "A gift was created",
                  "value": {
                    "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "attribution": {},
                    "mode": "test",
                    "status": "awaiting_address",
                    "outcome": "none",
                    "orderState": null,
                    "carrier": null,
                    "trackingNumber": null,
                    "trackingUrl": null,
                    "id": "8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b",
                    "cursor": "djE6MTI4Mzk=",
                    "type": "send.created",
                    "timestamp": "2026-10-11T15:04:05.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    },
    "send.gift_link_changed": {
      "post": {
        "operationId": "sendGiftLinkChangedWebhook",
        "tags": ["Webhooks"],
        "summary": "A gift link changed (issued, revoked, regifted, claimed or expired)",
        "description": "Sent to endpoints subscribed to `send.gift_link_changed` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendGiftLinkChangedEvent"
              },
              "examples": {
                "sendGiftLinkChanged": {
                  "summary": "A gift link changed (issued, revoked, regifted, claimed or expired)",
                  "value": {
                    "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "attribution": {},
                    "mode": "test",
                    "status": "awaiting_address",
                    "outcome": "none",
                    "orderState": null,
                    "carrier": null,
                    "trackingNumber": null,
                    "trackingUrl": null,
                    "giftLink": {
                      "state": "revoked",
                      "generation": 1,
                      "expiresAt": "2026-10-25T15:04:05.000Z"
                    },
                    "id": "4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a",
                    "cursor": "djE6MTI4NjE=",
                    "type": "send.gift_link_changed",
                    "timestamp": "2026-10-12T11:15:00.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    },
    "send.order_changed": {
      "post": {
        "operationId": "sendOrderChangedWebhook",
        "tags": ["Webhooks"],
        "summary": "The fulfillment order changed",
        "description": "Sent to endpoints subscribed to `send.order_changed` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendOrderChangedEvent"
              },
              "examples": {
                "sendOrderChanged": {
                  "summary": "The fulfillment order changed",
                  "value": {
                    "sendId": "send_7d9f1b3d5f7a9c1e3b5d7f9a1c3e5a7b",
                    "campaignId": "cmp_9a1c3e5f7b2d4f6a8c0e1b3d5f7a9c2e",
                    "attribution": {},
                    "mode": "live",
                    "status": "in_production",
                    "outcome": "none",
                    "orderState": "production",
                    "carrier": null,
                    "trackingNumber": null,
                    "trackingUrl": null,
                    "id": "0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e",
                    "cursor": "djE6MTI4ODg=",
                    "type": "send.order_changed",
                    "timestamp": "2026-10-13T09:00:00.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    },
    "send.address_confirmed": {
      "post": {
        "operationId": "sendAddressConfirmedWebhook",
        "tags": ["Webhooks"],
        "summary": "The recipient confirmed their address",
        "description": "Sent to endpoints subscribed to `send.address_confirmed` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendAddressConfirmedEvent"
              },
              "examples": {
                "sendAddressConfirmed": {
                  "summary": "The recipient confirmed their address",
                  "value": {
                    "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "attribution": {},
                    "mode": "test",
                    "status": "queued",
                    "outcome": "none",
                    "orderState": null,
                    "carrier": null,
                    "trackingNumber": null,
                    "trackingUrl": null,
                    "id": "6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c",
                    "cursor": "djE6MTI4NzA=",
                    "type": "send.address_confirmed",
                    "timestamp": "2026-10-12T16:45:00.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    },
    "send.link_opened": {
      "post": {
        "operationId": "sendLinkOpenedWebhook",
        "tags": ["Webhooks"],
        "summary": "The recipient opened their gift link",
        "description": "Sent to endpoints subscribed to `send.link_opened` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendLinkOpenedEvent"
              },
              "examples": {
                "sendLinkOpened": {
                  "summary": "The recipient opened their gift link",
                  "value": {
                    "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "attribution": {},
                    "mode": "test",
                    "status": "awaiting_address",
                    "outcome": "none",
                    "orderState": null,
                    "carrier": null,
                    "trackingNumber": null,
                    "trackingUrl": null,
                    "generation": 1,
                    "id": "5e7a9c1b3d5f7a9c1e3b5d7f9a1c3e5b",
                    "cursor": "djE6MTI4NDc=",
                    "type": "send.link_opened",
                    "timestamp": "2026-10-12T09:30:00.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    },
    "send.status_changed": {
      "post": {
        "operationId": "sendStatusChangedWebhook",
        "tags": ["Webhooks"],
        "summary": "The gift's status changed",
        "description": "Sent to endpoints subscribed to `send.status_changed` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendStatusChangedEvent"
              },
              "examples": {
                "sendStatusChanged": {
                  "summary": "The gift's status changed",
                  "value": {
                    "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "attribution": {},
                    "mode": "test",
                    "status": "shipped",
                    "outcome": "none",
                    "orderState": "shipped",
                    "carrier": "UPS",
                    "trackingNumber": "1Z999AA10123456784",
                    "trackingUrl": "https://www.ups.com/track?tracknum=1Z999AA10123456784",
                    "id": "3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c",
                    "cursor": "djE6MTI5MDI=",
                    "type": "send.status_changed",
                    "timestamp": "2026-10-15T18:20:00.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    },
    "send.outcome_reported": {
      "post": {
        "operationId": "sendOutcomeReportedWebhook",
        "tags": ["Webhooks"],
        "summary": "A reply or meeting was reported",
        "description": "Sent to endpoints subscribed to `send.outcome_reported` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendOutcomeReportedEvent"
              },
              "examples": {
                "sendOutcomeReported": {
                  "summary": "A reply or meeting was reported",
                  "value": {
                    "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "attribution": {},
                    "mode": "test",
                    "status": "delivered",
                    "outcome": "meeting_booked",
                    "orderState": null,
                    "carrier": null,
                    "trackingNumber": null,
                    "trackingUrl": null,
                    "source": "hubspot",
                    "externalEventId": "meeting-99812",
                    "occurredAt": "2026-10-20T17:00:00.000Z",
                    "id": "9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f",
                    "cursor": "djE6MTI5NDQ=",
                    "type": "send.outcome_reported",
                    "timestamp": "2026-10-20T17:05:00.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    },
    "send.tracking_changed": {
      "post": {
        "operationId": "sendTrackingChangedWebhook",
        "tags": ["Webhooks"],
        "summary": "Carrier tracking changed",
        "description": "Sent to endpoints subscribed to `send.tracking_changed` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendTrackingChangedEvent"
              },
              "examples": {
                "sendTrackingChanged": {
                  "summary": "Carrier tracking changed",
                  "value": {
                    "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "attribution": {},
                    "mode": "test",
                    "status": "shipped",
                    "outcome": "none",
                    "orderState": null,
                    "carrier": "UPS",
                    "trackingNumber": "1Z999AA10123456784",
                    "trackingUrl": "https://www.ups.com/track?tracknum=1Z999AA10123456784",
                    "id": "2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d",
                    "cursor": "djE6MTI5MDE=",
                    "type": "send.tracking_changed",
                    "timestamp": "2026-10-15T18:19:58.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    },
    "send.auto_approved": {
      "post": {
        "operationId": "sendAutoApprovedWebhook",
        "tags": ["Webhooks"],
        "summary": "A playbook's auto-approve rule approved and paid for a gift",
        "description": "Sent to endpoints subscribed to `send.auto_approved` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendAutoApprovedEvent"
              },
              "examples": {
                "sendAutoApproved": {
                  "summary": "A playbook's auto-approve rule approved and paid for a gift",
                  "value": {
                    "sendId": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b",
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "attribution": {},
                    "mode": "test",
                    "status": "awaiting_address",
                    "outcome": "none",
                    "orderState": null,
                    "carrier": null,
                    "trackingNumber": null,
                    "trackingUrl": null,
                    "id": "1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b",
                    "cursor": "djE6MTI4NDA=",
                    "type": "send.auto_approved",
                    "timestamp": "2026-10-11T15:04:05.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    },
    "playbook.person_waiting": {
      "post": {
        "operationId": "playbookPersonWaitingWebhook",
        "tags": ["Webhooks"],
        "summary": "A playbook person waits for a person",
        "description": "Sent to endpoints subscribed to `playbook.person_waiting` or `all`. Verify the signature as the Webhooks tag describes and deduplicate on the event ID.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlaybookPersonWaitingEvent"
              },
              "examples": {
                "playbookPersonWaiting": {
                  "summary": "A playbook person waits for a person",
                  "value": {
                    "campaignId": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "recipientId": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a",
                    "sourceSystem": "hubspot",
                    "externalId": "contact-4821",
                    "reason": "over_gift_limit",
                    "approvalUrl": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
                    "id": "7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a",
                    "type": "playbook.person_waiting",
                    "timestamp": "2026-10-11T15:04:05.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx acknowledges the delivery."
          },
          "default": {
            "description": "Anything else (or no answer in 10 seconds) is retried."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A workspace key from Settings → Integrations: `Authorization: Bearer gtm_<64 hex>`. It acts as the member who created it, in that member's role, in one workspace. Revoked or malformed keys get 401 AUTH_REQUIRED."
      },
      "mcpOAuth": {
        "type": "oauth2",
        "description": "OAuth 2.1 for MCP clients, accepted over REST only on the gift-link distribution routes (every other route answers 401). Public clients only: register at https://gtmswag.com/oauth/register (RFC 7591), use PKCE with S256, and send `resource=https://gtmswag.com/mcp` on both the authorization and token requests. Access tokens (`mco_access_…`) last 15 minutes; refresh tokens rotate on each use. Server metadata: https://gtmswag.com/.well-known/oauth-authorization-server. ChatGPT app tokens (`cgo_access_…`) are accepted on the same routes.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://gtmswag.com/oauth/authorize",
            "tokenUrl": "https://gtmswag.com/oauth/token",
            "refreshUrl": "https://gtmswag.com/oauth/token",
            "scopes": {
              "gifts:read": "View workspace gift plans and delivery progress.",
              "gifts:write": "Create and update gift drafts; over REST, save and remove source imports.",
              "gifts:links:read": "Retrieve private recipient claim links and download recipient CSV exports. Anyone with a claim link can use it."
            }
          }
        }
      },
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "gtm_session",
        "description": "A signed-in person's browser session at gtmswag.com. Human-only operations accept only this; writes must also come from the gtmswag.com origin. Agents cannot obtain it: hand the operation's `url` to a person."
      }
    },
    "parameters": {
      "AssetId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Uploaded file ID (asset_).",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100,
          "pattern": "^asset_[A-Za-z0-9_-]+$"
        },
        "example": "asset_9e1b3d5f7a9c1e3b5d7f9a1c3e5a7b9d"
      },
      "CampaignId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Campaign or playbook ID (cmp_).",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100,
          "pattern": "^cmp_[A-Za-z0-9_-]+$"
        },
        "example": "cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e"
      },
      "CheckoutId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Campaign checkout ID (cbo_).",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100,
          "pattern": "^cbo_[A-Za-z0-9_-]+$"
        },
        "example": "cbo_1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b"
      },
      "DeliveryId": {
        "name": "deliveryId",
        "in": "path",
        "required": true,
        "description": "Delivery `id` from GET /webhooks/{id}/deliveries (unique within its `source`).",
        "schema": {
          "type": "string",
          "pattern": "^[0-9]+$"
        },
        "example": "412"
      },
      "ExportId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Export ID (export_) from the create response.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100,
          "pattern": "^export_[A-Za-z0-9_-]+$"
        },
        "example": "export_4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c"
      },
      "InvitationId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Invitation ID (inv_).",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100,
          "pattern": "^inv_[A-Za-z0-9_-]+$"
        },
        "example": "inv_8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e"
      },
      "MemberId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The teammate's userId (usr_).",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100,
          "pattern": "^usr_[A-Za-z0-9_-]+$"
        },
        "example": "usr_5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d"
      },
      "RecipientId": {
        "name": "recipientId",
        "in": "path",
        "required": true,
        "description": "The item's recipientId from GET /billing/checkouts/{id}/items.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 300
        },
        "example": "recipient_8b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a"
      },
      "SendId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Gift (send) ID (send_).",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100,
          "pattern": "^send_[A-Za-z0-9_-]+$"
        },
        "example": "send_2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e1b"
      },
      "WebhookId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Webhook endpoint ID (wh_).",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100,
          "pattern": "^wh_[A-Za-z0-9_-]+$"
        },
        "example": "wh_6c8e0a2b4d6f8a0c2e4b6d8f0a2c4e6b"
      },
      "WebhookEventId": {
        "name": "X-GTM-Swag-Event-Id",
        "in": "header",
        "required": true,
        "description": "The event `id`; identical on every attempt. Deduplicate on it.",
        "schema": {
          "type": "string",
          "pattern": "^[a-f0-9]{32}$"
        },
        "example": "5e7a9c1b3d5f7a9c1e3b5d7f9a1c3e5b"
      },
      "WebhookSignature": {
        "name": "X-GTM-Swag-Signature",
        "in": "header",
        "required": true,
        "description": "`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" keyed with the endpoint secret>`. The example signs the compact JSON of the `send.link_opened` example with the secret from the `POST /webhooks` example, so a verifier can be tested against it.",
        "schema": {
          "type": "string",
          "pattern": "^t=[0-9]+,v1=[a-f0-9]{64}$"
        },
        "example": "t=1791797404,v1=888b95c4a882f0df7e4978eef22b2f730d9fcdc9f597c4d482ae5e647bcc47f8"
      }
    },
    "schemas": {
      "Asset": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "mime": {
            "type": "string"
          },
          "bytes": {
            "type": "integer"
          }
        },
        "required": ["id", "mime", "bytes"],
        "description": "An uploaded private file; use its `asset_` ID in campaigns and gifts."
      },
      "AssetResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": Asset}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Asset"
          }
        }
      },
      "Attribution": {
        "type": "object",
        "properties": {
          "externalId": {
            "type": "string",
            "maxLength": 200,
            "description": "External record ID (recipient contact ID)."
          },
          "source": {
            "type": "string",
            "maxLength": 200,
            "description": "Source system or list name."
          },
          "contactId": {
            "type": "string",
            "maxLength": 200,
            "description": "External CRM contact ID."
          },
          "accountId": {
            "type": "string",
            "maxLength": 200,
            "description": "External CRM account ID."
          },
          "opportunityId": {
            "type": "string",
            "maxLength": 200,
            "description": "External CRM opportunity ID."
          },
          "metadata": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Source labels; no secrets/PII."
          }
        },
        "additionalProperties": false,
        "description": "Reporting references; no secrets/PII."
      },
      "AutoApprovePolicy": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "perGiftMaxCents": {
            "type": "integer"
          },
          "enabledBy": {
            "type": "string"
          },
          "enabledAt": {
            "type": "string"
          }
        },
        "required": ["enabled", "perGiftMaxCents"],
        "description": "Auto-approve rule a signed-in owner or admin set in the web app. While enabled, a person added to this active playbook whose gift fits perGiftMaxCents, monthlyBudgetCents and the balance is approved and paid from the balance on enabledBy's behalf. Read-only through keys and connections."
      },
      "AutoApproveReason": {
        "type": "string",
        "enum": [
          "auto_approve_off",
          "over_gift_limit",
          "monthly_cap",
          "low_balance",
          "repeat_recipient",
          "photo_review",
          "age_restricted",
          "shipping_quote",
          "email_unverified",
          "blocked"
        ],
        "description": "Why the person waits for a person: auto_approve_off (no auto-approve on this playbook), over_gift_limit (the gift costs more than the per-gift limit), monthly_cap (the monthly budget is used up), low_balance (the balance cannot cover the gift; adding funds does not re-check waiting people), repeat_recipient (already gifted by another campaign), photo_review (a photo must be sourced or approved), age_restricted (alcohol always waits), shipping_quote (delivery is not priced yet, so these gifts always wait), email_unverified (the person who turned it on has not verified their email), blocked (anything else, such as an unavailable or unverified gift, or with mode live a person without a sender-supplied address)."
      },
      "Balance": {
        "type": "object",
        "properties": {
          "cents": {
            "type": "integer"
          },
          "mode": {
            "type": "string",
            "enum": ["test", "live"]
          },
          "lowBalance": {
            "type": "boolean",
            "description": "true when the balance cannot cover everyone waiting for approval, or one more gift from any active playbook (for an auto-approve playbook, its per-gift limit or the gift price if higher)."
          },
          "topUpUrl": {
            "type": "string",
            "description": "Where a person adds funds."
          }
        },
        "required": ["cents", "mode", "lowBalance", "topUpUrl"],
        "description": "The gift balance in the workspace's mode."
      },
      "BalanceMovement": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Movement ID (bal_)."
          },
          "kind": {
            "enum": ["topup", "debit", "credit", "adjustment"]
          },
          "cents": {
            "type": "integer"
          },
          "sendId": {
            "type": ["string", "null"]
          },
          "campaignId": {
            "type": ["string", "null"]
          },
          "note": {
            "type": ["string", "null"]
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "kind",
          "cents",
          "sendId",
          "campaignId",
          "note",
          "createdAt"
        ],
        "description": "One balance movement; `kind` gives the direction of the always-positive `cents`."
      },
      "BalanceMovementListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [BalanceMovement]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BalanceMovement"
            }
          }
        }
      },
      "BalanceResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": Balance}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Balance"
          }
        }
      },
      "BillingConfig": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "mode": {
            "type": "string",
            "enum": ["sandbox", "live", "disabled"]
          },
          "canPay": {
            "type": "boolean"
          }
        },
        "required": ["enabled", "mode", "canPay"],
        "description": "Whether campaign checkout is available in this workspace."
      },
      "BillingConfigResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": BillingConfig}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/BillingConfig"
          }
        }
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": ["draft", "active", "paused", "completed"]
          },
          "mode": {
            "type": "string",
            "enum": ["always_on", "batch", "single"]
          },
          "monthlyBudgetCents": {
            "type": "integer"
          },
          "autoApprove": {
            "$ref": "#/components/schemas/AutoApprovePolicy"
          },
          "policyVersion": {
            "type": "integer"
          },
          "recipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Recipient"
            }
          }
        },
        "required": ["id", "status", "mode", "policyVersion", "recipients"],
        "description": "A playbook (`mode:\"always_on\"`) or a batch or single campaign, with its roster, limits and `policyVersion`."
      },
      "CampaignListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [Campaign]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Campaign"
            }
          }
        }
      },
      "CampaignPreview": {
        "type": "object",
        "properties": {
          "campaignId": {
            "type": "string"
          },
          "policyVersion": {
            "type": "integer"
          },
          "recipientCount": {
            "type": "integer"
          },
          "totalCents": {
            "type": "integer"
          },
          "nextAction": {
            "type": "string",
            "enum": ["review", "provide_sender_address"],
            "description": "review: ready for human review, subject to blockers and any returned prepaidOffer. provide_sender_address: this draft needs sender-supplied US shipping details before it can be paid."
          },
          "unavailableReason": {
            "type": ["string", "null"],
            "enum": ["live_addressless_unavailable", null]
          },
          "prepaidOffer": {
            "type": "object",
            "properties": {
              "version": {
                "type": "string"
              },
              "productId": {
                "type": "string"
              },
              "unitCents": {
                "type": "integer"
              },
              "currency": {
                "type": "string",
                "enum": ["usd"]
              },
              "shippingStates": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "claimDays": {
                "type": "integer"
              },
              "qualificationVersion": {
                "type": "string"
              }
            },
            "required": [
              "version",
              "productId",
              "unitCents",
              "currency",
              "shippingStates",
              "claimDays",
              "qualificationVersion"
            ]
          },
          "fulfillmentRequirements": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "recipientId": {
                  "type": "string"
                },
                "recipientName": {
                  "type": "string"
                },
                "recipientEmail": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "photo_sourcing",
                    "address_confirmation",
                    "sender_address_required"
                  ]
                },
                "message": {
                  "type": "string"
                }
              },
              "required": [
                "recipientId",
                "recipientName",
                "recipientEmail",
                "kind",
                "message"
              ]
            }
          },
          "blockers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "campaignId",
          "policyVersion",
          "recipientCount",
          "totalCents",
          "nextAction",
          "unavailableReason"
        ],
        "description": "The exact total, blockers and next step for people without a gift yet. Creates nothing."
      },
      "CampaignPreviewResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": CampaignPreview}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/CampaignPreview"
          }
        }
      },
      "CampaignResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": Campaign}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Campaign"
          }
        }
      },
      "CampaignResults": {
        "type": "object",
        "properties": {
          "campaignId": {
            "type": "string"
          },
          "totalSends": {
            "type": "integer"
          },
          "committedCents": {
            "type": "integer"
          },
          "meetings": {
            "type": "integer"
          },
          "outcomeSource": {
            "type": "string",
            "enum": ["customer_reported"]
          }
        },
        "required": [
          "campaignId",
          "totalSends",
          "committedCents",
          "meetings",
          "outcomeSource"
        ],
        "description": "One campaign's gifts, committed spend and customer-reported meetings."
      },
      "CampaignResultsResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": CampaignResults}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/CampaignResults"
          }
        }
      },
      "CatalogProduct": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "name",
          "tagline",
          "description",
          "category",
          "priceCents",
          "shippingCents",
          "leadDays",
          "color",
          "image",
          "personalization",
          "occasion",
          "message",
          "verified"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Product ID; copy it into productId."
          },
          "name": {
            "type": "string"
          },
          "tagline": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "priceCents": {
            "type": "integer",
            "description": "Gift price in USD cents."
          },
          "shippingCents": {
            "type": "integer",
            "description": "Shipping in USD cents."
          },
          "leadDays": {
            "type": "string"
          },
          "color": {
            "type": "string"
          },
          "image": {
            "type": "string",
            "description": "Image path on https://gtmswag.com."
          },
          "personalization": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "occasion": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "verified": {
            "type": "boolean",
            "description": "False means planning estimates that still need confirmation."
          },
          "retired": {
            "type": "boolean",
            "description": "Kept for history; never choose a retired gift."
          },
          "available": {
            "type": "boolean"
          },
          "featured": {
            "type": "boolean"
          },
          "fixedPrice": {
            "type": "boolean"
          },
          "estimateIncludesDelivery": {
            "type": "boolean"
          },
          "priceQuoteRequired": {
            "type": "boolean"
          },
          "shippingQuoteRequired": {
            "type": "boolean"
          },
          "requiresArtwork": {
            "type": "boolean"
          },
          "requiresPortrait": {
            "type": "boolean"
          },
          "fulfillmentKind": {
            "enum": ["standard", "food", "alcohol"]
          },
          "catalogStatus": {
            "enum": ["sourced"]
          },
          "giftType": {
            "enum": [
              "desk",
              "treats",
              "surprises",
              "wearables",
              "drinks",
              "carry",
              "comfort"
            ]
          },
          "imageLabel": {
            "type": "string"
          },
          "deliveryNote": {
            "type": "string"
          },
          "dietaryNote": {
            "type": "string"
          },
          "example": {
            "type": "object",
            "properties": {
              "occasion": {
                "type": "string"
              },
              "artwork": {
                "type": "string"
              }
            }
          },
          "quoteDetails": {
            "type": "object",
            "properties": {
              "configuration": {
                "type": "string"
              },
              "decoration": {
                "type": "string"
              },
              "inputs": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "proof": {
                "type": "string"
              }
            }
          },
          "personalizationText": {
            "type": "object",
            "properties": {
              "label": {
                "type": "string"
              },
              "maxLength": {
                "type": "integer"
              },
              "maxLines": {
                "type": "integer"
              },
              "lineMaxLength": {
                "type": "integer"
              },
              "firstLineRequired": {
                "type": "boolean"
              },
              "allowedCharacters": {
                "type": "string"
              },
              "help": {
                "type": "string"
              }
            }
          },
          "recipientDetails": {
            "type": "array",
            "description": "Facts collected for each recipient in recipient.details, keyed by key. Required fields must be filled before approval.",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "help": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": ["text", "url"]
                },
                "maxLength": {
                  "type": "integer"
                },
                "required": {
                  "type": "boolean"
                }
              }
            }
          }
        },
        "description": "One gift of the catalog, with its price and requirements."
      },
      "CatalogProductListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [CatalogProduct]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogProduct"
            }
          }
        }
      },
      "Checkout": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "campaignId": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": [
              "creating",
              "open",
              "paid",
              "consumed",
              "expired",
              "cancelled"
            ]
          },
          "amountCents": {
            "type": "integer"
          },
          "remainingCount": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "campaignId",
          "state",
          "amountCents",
          "remainingCount"
        ],
        "description": "A campaign checkout with its state, amounts and invoice links."
      },
      "CheckoutItem": {
        "type": "object",
        "properties": {
          "recipientId": {
            "type": "string"
          },
          "recipientName": {
            "type": "string"
          },
          "amountCents": {
            "type": "integer"
          },
          "sendId": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "refundStatus": {
            "type": "string"
          },
          "canRequestRefund": {
            "type": "boolean"
          }
        },
        "required": [
          "recipientId",
          "recipientName",
          "amountCents",
          "state",
          "canRequestRefund"
        ],
        "description": "One recipient a live prepaid checkout paid for."
      },
      "CheckoutItemListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [CheckoutItem]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CheckoutItem"
            }
          }
        }
      },
      "CheckoutListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [Checkout]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Checkout"
            }
          }
        }
      },
      "CheckoutResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": Checkout}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Checkout"
          }
        }
      },
      "Customization": {
        "type": "object",
        "propertyNames": {
          "type": "string",
          "minLength": 1,
          "maxLength": 80
        },
        "additionalProperties": {
          "type": "string",
          "maxLength": 400
        },
        "description": "displayText: lettering; logoAssetId: artwork; giftLinkContactEmail: public sender contact; giftLinkWelcome: private-link welcome (400 chars, {{firstName}}/{{company}}), separate from the printed note."
      },
      "DistributionCounts": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer"
          },
          "ready": {
            "type": "integer"
          },
          "unavailable": {
            "type": "integer"
          }
        },
        "required": ["total", "ready", "unavailable"]
      },
      "DistributionRecordsPage": {
        "type": "object",
        "properties": {
          "version": {
            "const": 1,
            "type": "integer"
          },
          "records": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "recipient_id": {
                  "type": "string"
                },
                "source_system": {
                  "type": "string"
                },
                "external_id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "company": {
                  "type": "string"
                },
                "email": {
                  "type": "string"
                },
                "profile_url": {
                  "type": "string"
                },
                "campaign_id": {
                  "type": "string"
                },
                "gift_id": {
                  "type": "string"
                },
                "product_id": {
                  "type": "string"
                },
                "import_id": {
                  "type": "string"
                },
                "import_row_id": {
                  "type": "string"
                },
                "review_url": {
                  "type": "string"
                },
                "gift_link": {
                  "type": "string"
                },
                "gift_status": {
                  "type": "string"
                },
                "availability_reason": {
                  "type": "string"
                },
                "gift_expires_at": {
                  "type": "string"
                },
                "availability": {
                  "type": "string",
                  "enum": [
                    "awaiting_approval",
                    "preparing_links",
                    "ready",
                    "unavailable"
                  ]
                },
                "link_generation": {
                  "type": "integer"
                },
                "mode": {
                  "type": "string",
                  "enum": ["test", "live"]
                }
              },
              "required": [
                "recipient_id",
                "source_system",
                "external_id",
                "name",
                "company",
                "email",
                "profile_url",
                "campaign_id",
                "gift_id",
                "product_id",
                "import_id",
                "import_row_id",
                "review_url",
                "gift_link",
                "gift_status",
                "availability_reason",
                "gift_expires_at",
                "availability",
                "link_generation",
                "mode"
              ]
            }
          },
          "nextCursor": {
            "type": ["string", "null"]
          },
          "counts": {
            "$ref": "#/components/schemas/DistributionCounts"
          },
          "sourceImports": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceImport"
            }
          }
        },
        "required": [
          "version",
          "records",
          "nextCursor",
          "counts",
          "sourceImports"
        ],
        "description": "One page of a campaign's people with their private gift links; `nextCursor` is null on the last page."
      },
      "DistributionRecordsPageResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": DistributionRecordsPage}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/DistributionRecordsPage"
          }
        }
      },
      "EmailOrEmpty": {
        "default": "",
        "anyOf": [
          {
            "type": "string",
            "const": ""
          },
          {
            "type": "string",
            "maxLength": 254,
            "format": "email",
            "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
          }
        ],
        "description": "An email address, or an empty string for none. Both variants are strings, so the union has no discriminator."
      },
      "ErrorEnvelope": {
        "type": "object",
        "description": "Every error response, REST and MCP alike. Follow `nextAction` instead of guessing; `code` is stable, `error` is readable text.",
        "required": ["error", "code", "nextAction", "retryable"],
        "properties": {
          "error": {
            "type": "string",
            "description": "Readable reason."
          },
          "code": {
            "type": "string",
            "description": "Stable code, such as PLAYBOOK_OFF or RATE_LIMIT. Each operation lists the codes it returns."
          },
          "nextAction": {
            "type": "string",
            "enum": [
              "open_url",
              "reread_and_retry",
              "ask_user",
              "retry_later",
              "stop"
            ],
            "description": "open_url: a person resolves this at url; reread_and_retry: state changed, and a retry based on current state can succeed; ask_user: missing or corrected input is needed; retry_later: a retry after retryAfterMs can succeed; stop: retrying cannot succeed."
          },
          "url": {
            "type": "string",
            "description": "Absolute page where a person resolves this refusal."
          },
          "retryable": {
            "type": "boolean",
            "description": "True when retrying can succeed without a person."
          },
          "retryAfterMs": {
            "type": "integer",
            "description": "Milliseconds to wait before retrying."
          }
        }
      },
      "FundingRefundRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Refund request ID (cfr_)."
          }
        },
        "required": ["id"],
        "description": "A refund request for one prepaid gift."
      },
      "FundingRefundRequestResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": FundingRefundRequest}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/FundingRefundRequest"
          }
        }
      },
      "GiftCheckout": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Payment checkout ID (pay_)."
          },
          "state": {
            "enum": ["creating", "open", "hold", "paid", "expired", "refunded"],
            "description": "creating or open while it can be paid; then paid or expired."
          },
          "url": {
            "type": ["string", "null"],
            "description": "The Stripe payment page a person opens, once created."
          },
          "expiresAt": {
            "type": "integer",
            "description": "When the checkout expires, Unix seconds."
          },
          "totalCents": {
            "type": "integer"
          }
        },
        "required": ["id", "state", "url", "expiresAt", "totalCents"],
        "description": "A Stripe checkout for reviewed live gifts."
      },
      "GiftCheckoutList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Payment checkout ID (pay_)."
                },
                "state": {
                  "enum": [
                    "creating",
                    "open",
                    "hold",
                    "paid",
                    "expired",
                    "refunded"
                  ],
                  "description": "creating or open while it can be paid; then paid or expired."
                },
                "url": {
                  "type": ["string", "null"],
                  "description": "The Stripe payment page a person opens, once created."
                },
                "expiresAt": {
                  "type": "integer",
                  "description": "When the checkout expires, Unix seconds."
                },
                "totalCents": {
                  "type": "integer"
                },
                "idempotencyKey": {
                  "type": "string"
                },
                "sendIds": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "The gifts it pays for."
                }
              },
              "required": [
                "id",
                "state",
                "url",
                "expiresAt",
                "totalCents",
                "idempotencyKey",
                "sendIds"
              ]
            }
          }
        },
        "required": ["items"],
        "description": "Open payment checkouts for reviewed live gifts."
      },
      "GiftCheckoutListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": GiftCheckoutList}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/GiftCheckoutList"
          }
        }
      },
      "GiftCheckoutResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": GiftCheckout}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/GiftCheckout"
          }
        }
      },
      "GiftEvent": {
        "type": "object",
        "description": "One gift event, as `GET /events` returns it and as webhooks deliver it (no `data` wrapper).",
        "required": [
          "id",
          "cursor",
          "type",
          "timestamp",
          "sendId",
          "campaignId",
          "mode",
          "status",
          "outcome"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Event ID (32 hex); the X-GTM-Swag-Event-Id header. Deduplicate on it."
          },
          "cursor": {
            "type": "string",
            "description": "This event's position in GET /events."
          },
          "type": {
            "enum": [
              "send.created",
              "send.gift_link_changed",
              "send.order_changed",
              "send.address_confirmed",
              "send.link_opened",
              "send.status_changed",
              "send.outcome_reported",
              "send.tracking_changed",
              "send.auto_approved"
            ]
          },
          "timestamp": {
            "type": "string",
            "description": "When the event happened (ISO 8601, UTC)."
          },
          "sendId": {
            "type": "string",
            "description": "The gift (send_)."
          },
          "campaignId": {
            "type": ["string", "null"]
          },
          "attribution": {
            "type": "object",
            "description": "The gift's reporting references (externalId, source, contactId, accountId, opportunityId, metadata)."
          },
          "mode": {
            "enum": ["test", "live"]
          },
          "status": {
            "enum": [
              "awaiting_address",
              "queued",
              "in_production",
              "shipped",
              "delivered",
              "cancelled"
            ]
          },
          "outcome": {
            "enum": ["none", "replied", "meeting_booked", "meeting_held"]
          },
          "orderState": {
            "type": ["string", "null"]
          },
          "carrier": {
            "type": ["string", "null"]
          },
          "trackingNumber": {
            "type": ["string", "null"]
          },
          "trackingUrl": {
            "type": ["string", "null"]
          },
          "giftLink": {
            "type": "object",
            "description": "send.gift_link_changed: the link's state, generation and expiry (never its URL).",
            "properties": {
              "state": {
                "type": "string"
              },
              "generation": {
                "type": "integer"
              },
              "expiresAt": {
                "type": "string"
              },
              "redeemedAt": {
                "type": "string"
              }
            }
          },
          "generation": {
            "type": "integer",
            "description": "send.link_opened: the link generation that was opened."
          },
          "source": {
            "type": "string",
            "description": "send.outcome_reported: the reporting source."
          },
          "externalEventId": {
            "type": "string",
            "description": "send.outcome_reported: the source's event ID."
          },
          "occurredAt": {
            "type": "string",
            "description": "send.outcome_reported: when the outcome happened."
          }
        },
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "send.created": "#/components/schemas/SendCreatedEvent",
            "send.gift_link_changed": "#/components/schemas/SendGiftLinkChangedEvent",
            "send.order_changed": "#/components/schemas/SendOrderChangedEvent",
            "send.address_confirmed": "#/components/schemas/SendAddressConfirmedEvent",
            "send.link_opened": "#/components/schemas/SendLinkOpenedEvent",
            "send.status_changed": "#/components/schemas/SendStatusChangedEvent",
            "send.outcome_reported": "#/components/schemas/SendOutcomeReportedEvent",
            "send.tracking_changed": "#/components/schemas/SendTrackingChangedEvent",
            "send.auto_approved": "#/components/schemas/SendAutoApprovedEvent"
          }
        }
      },
      "GiftingReport": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": ["test", "live"]
          },
          "totals": {
            "type": "object",
            "properties": {
              "gifts": {
                "type": "integer"
              },
              "committedCents": {
                "type": "integer"
              }
            },
            "required": ["gifts", "committedCents"]
          },
          "campaigns": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "campaignId": {
                  "type": "string"
                },
                "gifts": {
                  "type": "integer"
                },
                "committedCents": {
                  "type": "integer"
                }
              },
              "required": ["campaignId", "gifts", "committedCents"]
            }
          },
          "outcomeSource": {
            "type": "string",
            "enum": ["team_reported"]
          }
        },
        "required": ["mode", "totals", "campaigns", "outcomeSource"],
        "description": "Delivery and value totals per campaign for one mode."
      },
      "GiftingReportResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": GiftingReport}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/GiftingReport"
          }
        }
      },
      "GiftLink": {
        "type": "object",
        "properties": {
          "sendId": {
            "type": "string"
          },
          "recipient": {
            "$ref": "#/components/schemas/Recipient"
          },
          "generation": {
            "type": "integer"
          },
          "messageVersion": {
            "type": "integer"
          },
          "state": {
            "type": "string",
            "enum": [
              "unclaimed",
              "redeemed",
              "revoked",
              "expired",
              "declined",
              "cancelled"
            ]
          },
          "canRegift": {
            "type": "boolean"
          },
          "valueCents": {
            "type": "integer"
          }
        },
        "required": [
          "sendId",
          "recipient",
          "generation",
          "messageVersion",
          "state",
          "canRegift",
          "valueCents"
        ],
        "description": "A private claim link: its state, value and the `generation` and `messageVersion` edits need."
      },
      "GiftLinkBranding": {
        "type": "object",
        "properties": {
          "senderName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Gift sender's name."
          },
          "senderCompany": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Gift sender's company."
          },
          "contactEmail": {
            "$ref": "#/components/schemas/EmailOrEmpty",
            "description": "Public sender contact email; empty hides it."
          },
          "logoAssetId": {
            "default": "",
            "type": "string",
            "maxLength": 100,
            "description": "Owned PNG/JPEG/WebP logo asset ID; empty hides it. Never a recipient portrait."
          }
        },
        "required": ["senderName", "senderCompany"],
        "additionalProperties": false,
        "description": "Recipient-facing sender details. Omit to preserve; applies to all selected links."
      },
      "GiftLinkExport": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "downloadUrl": {
            "type": "string"
          },
          "filename": {
            "type": "string"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "mode": {
            "type": "string",
            "enum": ["test", "live", "mixed"]
          },
          "counts": {
            "$ref": "#/components/schemas/DistributionCounts"
          },
          "excluded": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "recipient_id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "availability_reason": {
                  "type": "string"
                }
              },
              "required": ["recipient_id", "name", "availability_reason"]
            }
          },
          "earliestExpiry": {
            "type": ["string", "null"]
          }
        },
        "required": [
          "id",
          "downloadUrl",
          "filename",
          "columns",
          "mode",
          "counts",
          "excluded",
          "earliestExpiry"
        ],
        "description": "A gift-link CSV export to download within 24 hours."
      },
      "GiftLinkExportResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": GiftLinkExport}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/GiftLinkExport"
          }
        }
      },
      "GiftLinkListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [GiftLink]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GiftLink"
            }
          }
        }
      },
      "GiftLinkResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": GiftLink}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/GiftLink"
          }
        }
      },
      "GiftLinkSettings": {
        "type": "object",
        "properties": {
          "remindersEnabled": {
            "type": "boolean"
          },
          "version": {
            "type": "integer"
          }
        },
        "required": ["remindersEnabled", "version"],
        "description": "Retired invitation reminder settings; reminders are off."
      },
      "GiftLinkSettingsResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": GiftLinkSettings}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/GiftLinkSettings"
          }
        }
      },
      "GiftRefund": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Refund request ID (gref_ or cfr_)."
          },
          "sendId": {
            "type": "string"
          },
          "campaignId": {
            "type": "string"
          },
          "recipientName": {
            "type": "string"
          },
          "amountCents": {
            "type": "integer"
          },
          "mode": {
            "enum": ["test", "live"]
          },
          "status": {
            "enum": ["requested", "processing", "refunded", "declined"]
          },
          "note": {
            "type": ["string", "null"]
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          },
          "version": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "sendId",
          "campaignId",
          "recipientName",
          "amountCents",
          "mode",
          "status",
          "createdAt",
          "updatedAt",
          "version"
        ],
        "description": "A refund request for an unused paid gift."
      },
      "GiftRefundListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [GiftRefund]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GiftRefund"
            }
          }
        }
      },
      "GiftRefundResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": GiftRefund}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/GiftRefund"
          }
        }
      },
      "LaunchResult": {
        "type": "object",
        "properties": {
          "sends": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Send"
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "error": {
                  "type": "string"
                }
              },
              "required": ["name", "error"]
            }
          },
          "nextCursor": {
            "type": ["integer", "null"]
          }
        },
        "required": ["sends", "errors", "nextCursor"],
        "description": "One processed page of an approved batch roster; `nextCursor` is null once every position is done."
      },
      "LaunchResultResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": LaunchResult}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/LaunchResult"
          }
        }
      },
      "NoteSuggestion": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "source": {
            "enum": ["template", "ai"]
          }
        },
        "required": ["message", "source"],
        "description": "A suggested printed note. Nothing is saved."
      },
      "NoteSuggestionResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": NoteSuggestion}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/NoteSuggestion"
          }
        }
      },
      "OkResult": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          }
        },
        "required": ["ok"],
        "description": "The change was made."
      },
      "OkResultResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": OkResult}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/OkResult"
          }
        }
      },
      "PlaybookAddResult": {
        "type": "object",
        "properties": {
          "queued": {
            "type": "boolean",
            "description": "true while the person waits or is scheduled; false once a gift exists or they were skipped."
          },
          "recipientId": {
            "type": "string"
          },
          "alreadyQueued": {
            "type": "boolean"
          },
          "approvalUrl": {
            "type": "string",
            "description": "Where a signed-in owner or admin approves waiting gifts for this playbook."
          },
          "approval": {
            "$ref": "#/components/schemas/PlaybookApproval"
          }
        },
        "required": [
          "queued",
          "recipientId",
          "alreadyQueued",
          "approvalUrl",
          "approval"
        ],
        "description": "What happened to one person added to a playbook. Read `approval`."
      },
      "PlaybookAddResultResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": PlaybookAddResult}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/PlaybookAddResult"
          }
        }
      },
      "PlaybookApproval": {
        "description": "auto_approved: the auto-approve rule approved the gift and paid it from the balance (sendId set). approved: a person already approved it (sendId set). waiting: it waits for a person (reason set). scheduled: the auto-approve rule finishes it in the background. skipped: a person skipped this recipient.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PlaybookApprovalAutoApproved"
          },
          {
            "$ref": "#/components/schemas/PlaybookApprovalApproved"
          },
          {
            "$ref": "#/components/schemas/PlaybookApprovalWaiting"
          },
          {
            "$ref": "#/components/schemas/PlaybookApprovalScheduled"
          },
          {
            "$ref": "#/components/schemas/PlaybookApprovalSkipped"
          }
        ],
        "discriminator": {
          "propertyName": "state",
          "mapping": {
            "auto_approved": "#/components/schemas/PlaybookApprovalAutoApproved",
            "approved": "#/components/schemas/PlaybookApprovalApproved",
            "waiting": "#/components/schemas/PlaybookApprovalWaiting",
            "scheduled": "#/components/schemas/PlaybookApprovalScheduled",
            "skipped": "#/components/schemas/PlaybookApprovalSkipped"
          }
        }
      },
      "PlaybookApprovalApproved": {
        "type": "object",
        "description": "A person already approved the gift.",
        "required": ["state", "sendId"],
        "properties": {
          "state": {
            "type": "string",
            "const": "approved"
          },
          "sendId": {
            "type": "string",
            "description": "The gift (send_)."
          }
        }
      },
      "PlaybookApprovalAutoApproved": {
        "type": "object",
        "description": "The playbook's auto-approve rule approved the gift and paid it from the balance.",
        "required": ["state", "sendId"],
        "properties": {
          "state": {
            "type": "string",
            "const": "auto_approved"
          },
          "sendId": {
            "type": "string",
            "description": "The gift (send_)."
          }
        }
      },
      "PlaybookApprovalScheduled": {
        "type": "object",
        "description": "The auto-approve rule finishes this person in the background; watch `GET /events` for `send.auto_approved`.",
        "required": ["state"],
        "properties": {
          "state": {
            "type": "string",
            "const": "scheduled"
          }
        }
      },
      "PlaybookApprovalSkipped": {
        "type": "object",
        "description": "A person skipped this recipient; do not add them again.",
        "required": ["state"],
        "properties": {
          "state": {
            "type": "string",
            "const": "skipped"
          }
        }
      },
      "PlaybookApprovalWaiting": {
        "type": "object",
        "description": "The person waits for a person to approve; `reason` says why. Nothing is charged or sent.",
        "required": ["state", "reason"],
        "properties": {
          "state": {
            "type": "string",
            "const": "waiting"
          },
          "reason": {
            "$ref": "#/components/schemas/AutoApproveReason"
          }
        }
      },
      "PlaybookPersonWaitingEvent": {
        "type": "object",
        "description": "A playbook person left waiting for a person, sent once per new reason. Webhook only (not in GET /events).",
        "required": [
          "id",
          "type",
          "timestamp",
          "campaignId",
          "recipientId",
          "reason",
          "approvalUrl"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Event ID (32 hex); the X-GTM-Swag-Event-Id header."
          },
          "type": {
            "const": "playbook.person_waiting"
          },
          "timestamp": {
            "type": "string"
          },
          "campaignId": {
            "type": "string",
            "description": "The playbook (cmp_)."
          },
          "recipientId": {
            "type": "string"
          },
          "sourceSystem": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "reason": {
            "$ref": "#/components/schemas/AutoApproveReason"
          },
          "approvalUrl": {
            "type": "string",
            "description": "Hand this to a person to approve."
          }
        }
      },
      "QueueAutoApproveState": {
        "description": "Present when the playbook's auto-approve is on: scheduled while it finishes in the background, or waiting with the reason it was left for a person.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PlaybookApprovalScheduled"
          },
          {
            "$ref": "#/components/schemas/PlaybookApprovalWaiting"
          }
        ],
        "discriminator": {
          "propertyName": "state",
          "mapping": {
            "scheduled": "#/components/schemas/PlaybookApprovalScheduled",
            "waiting": "#/components/schemas/PlaybookApprovalWaiting"
          }
        }
      },
      "QueueItem": {
        "type": "object",
        "properties": {
          "campaignId": {
            "type": "string"
          },
          "campaignName": {
            "type": "string"
          },
          "productId": {
            "type": "string"
          },
          "recipientId": {
            "type": "string"
          },
          "recipient": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": "string"
              },
              "company": {
                "type": "string"
              }
            },
            "required": ["name"]
          },
          "message": {
            "type": "string"
          },
          "priceCents": {
            "type": "integer"
          },
          "blockers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "approvalUrl": {
            "type": "string"
          },
          "autoApprove": {
            "$ref": "#/components/schemas/QueueAutoApproveState"
          }
        },
        "required": [
          "campaignId",
          "campaignName",
          "productId",
          "recipientId",
          "recipient",
          "message",
          "priceCents",
          "blockers",
          "approvalUrl"
        ],
        "description": "A person waiting for approval in an active playbook."
      },
      "QueueItemListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [QueueItem]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QueueItem"
            }
          }
        }
      },
      "Quote": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "totalCents": {
            "type": "integer"
          },
          "expiresAt": {
            "type": "string"
          },
          "testMode": {
            "type": "boolean"
          },
          "subtotalCents": {
            "type": "integer"
          },
          "shippingCents": {
            "type": "integer"
          },
          "taxCents": {
            "type": "integer"
          },
          "taxPending": {
            "type": "boolean"
          },
          "attribution": {
            "type": "object"
          }
        },
        "required": ["id", "totalCents", "expiresAt", "testMode"],
        "description": "A 15-minute quote for one roster person. It never sends or pays."
      },
      "QuoteResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": Quote}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Quote"
          }
        }
      },
      "Recipient": {
        "type": "object",
        "properties": {
          "recipientId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "sourceSystem": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "profileUrl": {
            "type": "string"
          },
          "importId": {
            "type": "string"
          },
          "importRowId": {
            "type": "string"
          },
          "addressMode": {
            "type": "string",
            "enum": ["known", "confirm"]
          }
        },
        "required": ["recipientId", "name", "email", "company"]
      },
      "RecipientInput": {
        "type": "object",
        "properties": {
          "name": {
            "default": "",
            "type": "string",
            "maxLength": 200,
            "description": "Recipient's full name."
          },
          "recipientId": {
            "type": "string",
            "pattern": "^recipient_[a-f0-9]{32}$",
            "description": "Stable workspace recipient ID; never infer from a name."
          },
          "sourceSystem": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Original source system name; pair with externalId for stable matching."
          },
          "profileUrl": {
            "type": "string",
            "maxLength": 500,
            "format": "uri",
            "description": "Supplied personal profile URL; photo sourcing requires separate permission."
          },
          "importId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 150,
            "description": "Stable customer import ID; reuse with identical retry data."
          },
          "importRowId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 150,
            "description": "Stable source row ID within an import."
          },
          "photo": {
            "$ref": "#/components/schemas/RecipientPhoto"
          },
          "adultRecipientConfirmed": {
            "type": "boolean",
            "description": "Explicit 21+ and adult-signature confirmation."
          },
          "assetIds": {
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^asset_[a-f0-9]{32}$"
            },
            "description": "Owned artwork asset IDs uploaded to this workspace."
          },
          "externalId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "External record ID (recipient contact ID)."
          },
          "email": {
            "$ref": "#/components/schemas/EmailOrEmpty",
            "description": "Recipient or teammate email address."
          },
          "company": {
            "default": "",
            "type": "string",
            "maxLength": 200,
            "description": "Recipient company; used for {{company}}."
          },
          "title": {
            "type": "string",
            "maxLength": 200,
            "description": "Recipient's job title."
          },
          "context": {
            "type": "string",
            "maxLength": 2000,
            "description": "Recipient background from customer."
          },
          "customTag": {
            "type": "string",
            "maxLength": 200,
            "description": "Value for {{custom}} in this note."
          },
          "address": {
            "type": "string",
            "maxLength": 200,
            "description": "Street and unit; required when known."
          },
          "city": {
            "type": "string",
            "maxLength": 200,
            "description": "US city; required when known."
          },
          "state": {
            "type": "string",
            "maxLength": 2,
            "description": "US state/DC code; required when known."
          },
          "zip": {
            "type": "string",
            "maxLength": 10,
            "description": "US ZIP/ZIP+4; required when known."
          },
          "country": {
            "default": "US",
            "type": "string",
            "const": "US",
            "description": "Delivery country; US only."
          },
          "addressMode": {
            "default": "confirm",
            "type": "string",
            "enum": ["known", "confirm"],
            "description": "known: complete sender-supplied US shipping address. confirm: address unknown; the recipient confirms it through a private gift link where the workspace allows it, including a qualified prepaid offer shown on the campaign preview. Otherwise live address-free gifts are refused with LIVE_ADDRESSLESS_UNAVAILABLE."
          },
          "message": {
            "type": "string",
            "maxLength": 500,
            "description": "Printed note; blank uses campaign fallback."
          },
          "details": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "pattern": "^[a-zA-Z][a-zA-Z0-9]{0,39}$"
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Per-recipient gift details keyed by the gift's recipientDetails keys, such as companyLogo or team. Required ones must be filled before approval."
          }
        },
        "additionalProperties": false
      },
      "RecipientPhoto": {
        "description": "Portrait upload or LinkedIn sourcing.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/RecipientPhotoUpload"
          },
          {
            "$ref": "#/components/schemas/RecipientPhotoLinkedIn"
          }
        ],
        "discriminator": {
          "propertyName": "source",
          "mapping": {
            "upload": "#/components/schemas/RecipientPhotoUpload",
            "linkedin": "#/components/schemas/RecipientPhotoLinkedIn"
          }
        }
      },
      "RecipientPhotoChange": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/RecipientPhotoChangeApprove"
          },
          {
            "$ref": "#/components/schemas/RecipientPhotoChangeReplace"
          },
          {
            "$ref": "#/components/schemas/RecipientPhotoChangeReject"
          }
        ],
        "discriminator": {
          "propertyName": "action",
          "mapping": {
            "approve": "#/components/schemas/RecipientPhotoChangeApprove",
            "replace": "#/components/schemas/RecipientPhotoChangeReplace",
            "reject": "#/components/schemas/RecipientPhotoChangeReject"
          }
        }
      },
      "RecipientPhotoChangeApprove": {
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "The gift's current portrait.version."
          },
          "action": {
            "type": "string",
            "const": "approve",
            "description": "Photo review action; approval needs customer permission."
          },
          "rightsConfirmed": {
            "type": "boolean",
            "const": true,
            "description": "True only with explicit photo-use permission."
          }
        },
        "required": ["version", "action", "rightsConfirmed"],
        "additionalProperties": false
      },
      "RecipientPhotoChangeReject": {
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "The gift's current portrait.version."
          },
          "action": {
            "type": "string",
            "const": "reject",
            "description": "Photo review action; approval needs customer permission."
          }
        },
        "required": ["version", "action"],
        "additionalProperties": false
      },
      "RecipientPhotoChangeReplace": {
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "The gift's current portrait.version."
          },
          "action": {
            "type": "string",
            "const": "replace",
            "description": "Photo review action; approval needs customer permission."
          },
          "assetId": {
            "type": "string",
            "pattern": "^asset_[a-f0-9]{32}$",
            "description": "Owned portrait asset_ ID from upload/import."
          },
          "rightsConfirmed": {
            "type": "boolean",
            "const": true,
            "description": "True only with explicit photo-use permission."
          }
        },
        "required": ["version", "action", "assetId"],
        "additionalProperties": false
      },
      "RecipientPhotoLinkedIn": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "const": "linkedin",
            "description": "upload: owned asset; linkedin: staff sourcing."
          },
          "profileUrl": {
            "type": "string",
            "maxLength": 500,
            "format": "uri",
            "description": "Supplied personal profile URL; photo sourcing requires separate permission."
          }
        },
        "required": ["source", "profileUrl"],
        "additionalProperties": false
      },
      "RecipientPhotoUpload": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "const": "upload",
            "description": "upload: owned asset; linkedin: staff sourcing."
          },
          "assetId": {
            "type": "string",
            "pattern": "^asset_[a-f0-9]{32}$",
            "description": "Owned portrait asset_ ID from upload/import."
          },
          "rightsConfirmed": {
            "type": "boolean",
            "const": true,
            "description": "True only with explicit photo-use permission."
          }
        },
        "required": ["source", "assetId"],
        "additionalProperties": false
      },
      "RepeatRecipient": {
        "type": "object",
        "properties": {
          "recipientId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "priorSendId": {
            "type": "string"
          },
          "approved": {
            "type": "boolean"
          }
        },
        "required": ["recipientId", "name", "email", "priorSendId", "approved"],
        "description": "A roster person already gifted by another campaign."
      },
      "RepeatRecipientListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [RepeatRecipient]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RepeatRecipient"
            }
          }
        }
      },
      "Send": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "recipient": {
            "$ref": "#/components/schemas/Recipient"
          },
          "campaignId": {
            "type": ["string", "null"]
          },
          "status": {
            "type": "string",
            "enum": [
              "awaiting_address",
              "queued",
              "in_production",
              "shipped",
              "delivered",
              "cancelled"
            ]
          },
          "totalCents": {
            "type": "integer"
          },
          "testMode": {
            "type": "boolean"
          },
          "fundedBy": {
            "type": "string",
            "enum": ["balance"],
            "description": "balance: the gift was paid from the workspace balance when it was approved; it never needs a checkout."
          },
          "autoApproved": {
            "type": "boolean",
            "description": "true when the playbook's auto-approve rule approved the gift rather than a person."
          }
        },
        "required": [
          "id",
          "recipient",
          "campaignId",
          "status",
          "totalCents",
          "testMode"
        ],
        "description": "One gift (send) with its immutable mode, status, outcome and timeline."
      },
      "SendAddressConfirmedEvent": {
        "description": "The recipient confirmed their address.",
        "allOf": [
          {
            "$ref": "#/components/schemas/GiftEvent"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send.address_confirmed"
              }
            }
          }
        ]
      },
      "SendAutoApprovedEvent": {
        "description": "A playbook's auto-approve rule approved and paid for a gift.",
        "allOf": [
          {
            "$ref": "#/components/schemas/GiftEvent"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send.auto_approved"
              }
            }
          }
        ]
      },
      "SendCreatedEvent": {
        "description": "A gift was created.",
        "allOf": [
          {
            "$ref": "#/components/schemas/GiftEvent"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send.created"
              }
            }
          }
        ]
      },
      "SendGiftLinkChangedEvent": {
        "description": "A gift link changed (issued, revoked, regifted, claimed or expired).",
        "allOf": [
          {
            "$ref": "#/components/schemas/GiftEvent"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send.gift_link_changed"
              }
            }
          }
        ]
      },
      "SendLinkOpenedEvent": {
        "description": "The recipient opened their gift link.",
        "allOf": [
          {
            "$ref": "#/components/schemas/GiftEvent"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send.link_opened"
              }
            }
          }
        ]
      },
      "SendListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [Send]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Send"
            }
          }
        }
      },
      "SendOrderChangedEvent": {
        "description": "The fulfillment order changed.",
        "allOf": [
          {
            "$ref": "#/components/schemas/GiftEvent"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send.order_changed"
              }
            }
          }
        ]
      },
      "SendOutcomeReportedEvent": {
        "description": "A reply or meeting was reported.",
        "allOf": [
          {
            "$ref": "#/components/schemas/GiftEvent"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send.outcome_reported"
              }
            }
          }
        ]
      },
      "SendResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": Send}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Send"
          }
        }
      },
      "SendStatusChangedEvent": {
        "description": "The gift's status changed.",
        "allOf": [
          {
            "$ref": "#/components/schemas/GiftEvent"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send.status_changed"
              }
            }
          }
        ]
      },
      "SendTrackingChangedEvent": {
        "description": "Carrier tracking changed.",
        "allOf": [
          {
            "$ref": "#/components/schemas/GiftEvent"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "send.tracking_changed"
              }
            }
          }
        ]
      },
      "Session": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Member user ID (usr_)."
          },
          "teamId": {
            "type": "string",
            "description": "Workspace ID (team_)."
          },
          "teamRole": {
            "enum": ["owner", "admin", "member"]
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "emailVerified": {
            "type": "boolean"
          },
          "isAdmin": {
            "type": "boolean",
            "description": "Always false for a key."
          },
          "isDemo": {
            "type": "boolean"
          },
          "liveEnabled": {
            "type": "boolean"
          },
          "workspaceMode": {
            "enum": ["test", "live"]
          }
        },
        "required": [
          "id",
          "teamId",
          "teamRole",
          "name",
          "email",
          "company",
          "emailVerified",
          "isAdmin",
          "isDemo",
          "liveEnabled",
          "workspaceMode"
        ],
        "description": "The member a workspace key acts as."
      },
      "SessionResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": Session | null}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Session"
              },
              {
                "type": "null"
              }
            ],
            "description": "A Session, or null when there is none."
          }
        }
      },
      "SkippedPerson": {
        "type": "object",
        "properties": {
          "campaignId": {
            "type": "string"
          },
          "campaignName": {
            "type": "string"
          },
          "recipientId": {
            "type": "string"
          },
          "recipient": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "company": {
                "type": "string"
              },
              "title": {
                "type": "string"
              }
            },
            "required": ["name"]
          },
          "reason": {
            "type": "string"
          },
          "skippedAt": {
            "type": "string"
          }
        },
        "required": [
          "campaignId",
          "campaignName",
          "recipientId",
          "recipient",
          "reason",
          "skippedAt"
        ],
        "description": "A playbook person a teammate skipped."
      },
      "SkippedPersonListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [SkippedPerson]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkippedPerson"
            }
          }
        }
      },
      "SkipResult": {
        "type": "object",
        "properties": {
          "skipped": {
            "type": "boolean"
          }
        },
        "required": ["skipped"],
        "description": "Whether the person is skipped now."
      },
      "SkipResultResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": SkipResult}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/SkipResult"
          }
        }
      },
      "SourceImport": {
        "type": "object",
        "properties": {
          "importId": {
            "type": "string"
          },
          "headers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "retainedColumnIndices": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "totalRows": {
            "type": "integer"
          },
          "complete": {
            "type": "boolean"
          }
        },
        "required": [
          "importId",
          "headers",
          "retainedColumnIndices",
          "totalRows",
          "complete"
        ],
        "description": "Original source columns kept with a campaign's recipients for exports."
      },
      "SourceImportResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": SourceImport}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/SourceImport"
          }
        }
      },
      "SourceUploadProgress": {
        "type": "object",
        "properties": {
          "uploadId": {
            "type": "string"
          },
          "receivedParts": {
            "type": "integer"
          },
          "partCount": {
            "type": "integer"
          },
          "complete": {
            "type": "boolean"
          },
          "sourceImport": {
            "$ref": "#/components/schemas/SourceImport"
          },
          "retryAfterMs": {
            "type": "integer"
          }
        },
        "required": ["uploadId", "receivedParts", "partCount", "complete"],
        "description": "Progress of a source import uploaded in parts."
      },
      "SourceUploadProgressResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": SourceUploadProgress}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/SourceUploadProgress"
          }
        }
      },
      "TeamInvitation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": ["pending", "accepted", "revoked", "expired"]
          }
        },
        "required": ["id", "email", "status"],
        "description": "An invitation to join the workspace."
      },
      "TeamInvitationCreated": {
        "type": "object",
        "properties": {
          "invitation": {
            "$ref": "#/components/schemas/TeamInvitation"
          },
          "inviteUrl": {
            "type": "string"
          },
          "emailQueued": {
            "type": "boolean"
          }
        },
        "required": ["invitation", "inviteUrl", "emailQueued"],
        "description": "The new invitation and its private `inviteUrl` (valid 7 days)."
      },
      "TeamInvitationCreatedResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": TeamInvitationCreated}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/TeamInvitationCreated"
          }
        }
      },
      "TeamInvitationListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [TeamInvitation]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TeamInvitation"
            }
          }
        }
      },
      "TeamMember": {
        "type": "object",
        "properties": {
          "userId": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": ["owner", "admin", "member"]
          }
        },
        "required": ["userId", "email", "role"],
        "description": "A workspace member and their role."
      },
      "TeamMemberListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [TeamMember]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TeamMember"
            }
          }
        }
      },
      "TeamMemberResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": TeamMember}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/TeamMember"
          }
        }
      },
      "TopUpSession": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "sessionId": {
            "type": "string"
          }
        },
        "required": ["url", "sessionId"],
        "description": "The Stripe payment page a person opens to add funds."
      },
      "TopUpSessionResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": TopUpSession}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/TopUpSession"
          }
        }
      },
      "Tracking": {
        "type": "object",
        "properties": {
          "sendId": {
            "type": "string"
          },
          "campaignId": {
            "type": ["string", "null"]
          },
          "status": {
            "type": "string",
            "enum": [
              "awaiting_address",
              "queued",
              "in_production",
              "shipped",
              "delivered",
              "cancelled"
            ]
          },
          "outcome": {
            "type": "string",
            "enum": ["none", "replied", "meeting_booked", "meeting_held"]
          },
          "mode": {
            "type": "string",
            "enum": ["test", "live"]
          }
        },
        "required": ["sendId", "campaignId", "status", "outcome", "mode"],
        "description": "A privacy-minimized status snapshot of one gift."
      },
      "TrackingEventsPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GiftEvent"
            }
          },
          "nextCursor": {
            "type": "string",
            "description": "Always set: store it and send it as cursor next time."
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "required": ["items", "nextCursor", "hasMore"],
        "description": "Events after the cursor, oldest first. Store `nextCursor` (always set) and poll again now when `hasMore`."
      },
      "TrackingEventsPageResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": TrackingEventsPage}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/TrackingEventsPage"
          }
        }
      },
      "TrackingPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tracking"
            }
          },
          "nextCursor": {
            "type": ["string", "null"]
          }
        },
        "required": ["items", "nextCursor"],
        "description": "One page of the gift status snapshot; `nextCursor` is null on the last page. Not a change feed."
      },
      "TrackingPageResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": TrackingPage}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/TrackingPage"
          }
        }
      },
      "TrackingResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": Tracking}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Tracking"
          }
        }
      },
      "UrlOrEmpty": {
        "default": "",
        "anyOf": [
          {
            "type": "string",
            "const": ""
          },
          {
            "type": "string",
            "format": "uri"
          }
        ],
        "description": "An absolute URL, or an empty string for none. Both variants are strings, so the union has no discriminator."
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": ["id", "url", "events", "createdAt"],
        "description": "A webhook endpoint and the event types it receives."
      },
      "WebhookDeliveriesPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer",
                  "description": "Delivery ID, unique per source."
                },
                "event_seq": {
                  "type": "integer"
                },
                "type": {
                  "type": "string"
                },
                "source": {
                  "enum": ["gift", "playbook"]
                },
                "state": {
                  "enum": ["pending", "sending", "delivered", "dead"]
                },
                "attempts": {
                  "type": "integer"
                },
                "next_at": {
                  "type": "integer",
                  "description": "Next attempt, Unix ms."
                },
                "last_status": {
                  "type": ["integer", "null"]
                },
                "last_error": {
                  "type": ["string", "null"]
                }
              },
              "required": [
                "id",
                "event_seq",
                "type",
                "source",
                "state",
                "attempts",
                "next_at",
                "last_status",
                "last_error"
              ]
            }
          },
          "nextBefore": {
            "type": ["integer", "null"]
          }
        },
        "required": ["items", "nextBefore"],
        "description": "One page of an endpoint's deliveries, newest first; pass `nextBefore` as `before`."
      },
      "WebhookDeliveriesPageResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": WebhookDeliveriesPage}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/WebhookDeliveriesPage"
          }
        }
      },
      "WebhookListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [Webhook]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          }
        }
      },
      "WebhookWithSecret": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "secret": {
            "type": "string"
          }
        },
        "required": ["id", "url", "events", "secret"],
        "description": "A new webhook endpoint with its signing `secret`, shown only once."
      },
      "WebhookWithSecretResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": WebhookWithSecret}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/WebhookWithSecret"
          }
        }
      },
      "WorkflowGuide": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": ["test", "live"]
          },
          "connectorCanSend": {
            "type": "boolean"
          },
          "approvalRequired": {
            "type": "boolean"
          },
          "reviewUrlTemplate": {
            "type": "string"
          },
          "usageOrder": {
            "type": "string"
          },
          "steps": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "batchSteps": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "tracking": {
            "type": "string"
          },
          "limits": {
            "type": "object",
            "properties": {
              "sourceUploadParts": {
                "type": "integer"
              },
              "sourceUploadSerializedBytes": {
                "type": "integer"
              },
              "sourceUploadExpiryHours": {
                "type": "integer"
              }
            },
            "required": [
              "sourceUploadParts",
              "sourceUploadSerializedBytes",
              "sourceUploadExpiryHours"
            ]
          },
          "recovery": {
            "type": "object",
            "properties": {
              "LIVE_ADDRESSLESS_UNAVAILABLE": {
                "type": "string"
              },
              "CAPABILITY_RETIRED": {
                "type": "string"
              },
              "UPLOAD_CAPACITY": {
                "type": "string"
              },
              "INSUFFICIENT_BALANCE": {
                "type": "string"
              },
              "BUDGET_CAP": {
                "type": "string"
              },
              "PLAYBOOK_OFF": {
                "type": "string"
              },
              "PLAYBOOK_BUSY": {
                "type": "string"
              },
              "NOT_ALWAYS_ON": {
                "type": "string"
              },
              "APPROVAL_REQUIRED": {
                "type": "string"
              },
              "MODE_LOCKED": {
                "type": "string"
              },
              "RECIPIENT_SKIPPED": {
                "type": "string"
              },
              "INSUFFICIENT_SCOPE": {
                "type": "string"
              },
              "AUTH_REQUIRED": {
                "type": "string"
              }
            },
            "required": [
              "LIVE_ADDRESSLESS_UNAVAILABLE",
              "CAPABILITY_RETIRED",
              "UPLOAD_CAPACITY",
              "INSUFFICIENT_BALANCE",
              "BUDGET_CAP",
              "PLAYBOOK_OFF",
              "PLAYBOOK_BUSY",
              "NOT_ALWAYS_ON",
              "APPROVAL_REQUIRED",
              "MODE_LOCKED",
              "RECIPIENT_SKIPPED",
              "INSUFFICIENT_SCOPE",
              "AUTH_REQUIRED"
            ]
          }
        },
        "required": [
          "mode",
          "connectorCanSend",
          "approvalRequired",
          "reviewUrlTemplate",
          "usageOrder",
          "steps",
          "batchSteps",
          "tracking",
          "limits",
          "recovery"
        ],
        "description": "What this key may do in this workspace, the playbook-first and batch steps, limits and a recovery rule per error code."
      },
      "WorkflowGuideResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": WorkflowGuide}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/WorkflowGuide"
          }
        }
      },
      "Workspace": {
        "type": "object",
        "properties": {
          "teamId": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "role": {
            "enum": ["owner", "admin", "member"]
          },
          "isDemo": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          }
        },
        "required": ["teamId", "company", "role", "isDemo", "active"],
        "description": "A workspace the caller belongs to."
      },
      "WorkspaceListResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": [Workspace]}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Workspace"
            }
          }
        }
      },
      "WorkspaceSettings": {
        "type": "object",
        "properties": {
          "company": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "meetingUrl": {
            "type": "string"
          },
          "website": {
            "type": "string"
          },
          "brandColor": {
            "type": "string"
          },
          "webhookUrl": {
            "type": "string"
          }
        },
        "required": [
          "company",
          "name",
          "meetingUrl",
          "website",
          "brandColor",
          "webhookUrl"
        ],
        "description": "The defaults new campaigns use."
      },
      "WorkspaceSettingsResponse": {
        "type": "object",
        "description": "The success body: `{\"data\": WorkspaceSettings}`.",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/WorkspaceSettings"
          }
        }
      }
    },
    "examples": {
      "ACCOUNT_REQUIRED": {
        "summary": "ACCOUNT_REQUIRED",
        "description": "Returned when the workspace is a demo.",
        "value": {
          "error": "Create an account to invite your team.",
          "code": "ACCOUNT_REQUIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "ADULT_RECIPIENT_REQUIRED": {
        "summary": "ADULT_RECIPIENT_REQUIRED",
        "description": "Returned when an alcohol gift without `adultRecipientConfirmed:true`.",
        "value": {
          "error": "Confirm Jamie Chen is 21 or older and can receive an adult-signature delivery.",
          "code": "ADULT_RECIPIENT_REQUIRED",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "ALLOCATION_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when no such paid item on the checkout.",
        "value": {
          "error": "Paid gift allocation not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "ALREADY_APPROVED": {
        "summary": "ALREADY_APPROVED",
        "description": "Returned when another approval for the same person is in progress.",
        "value": {
          "error": "This gift was just approved by someone else.",
          "code": "ALREADY_APPROVED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "ALREADY_MEMBER": {
        "summary": "ALREADY_MEMBER",
        "description": "Returned when the email already belongs to a member.",
        "value": {
          "error": "This person is already a workspace member. Change their role from the members list.",
          "code": "ALREADY_MEMBER",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "ALWAYS_ON_BALANCE_FUNDED": {
        "summary": "ALWAYS_ON_BALANCE_FUNDED",
        "description": "Returned when the campaign is a playbook.",
        "value": {
          "error": "Always-on campaigns are funded from your balance, not at checkout.",
          "code": "ALWAYS_ON_BALANCE_FUNDED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "APPROVAL_REQUIRED": {
        "summary": "APPROVAL_REQUIRED",
        "description": "Returned when the campaign is a playbook; its gifts go through the approval queue.",
        "value": {
          "error": "Always-on campaigns send gifts only through approval.",
          "code": "APPROVAL_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
          "retryable": false
        }
      },
      "APPROVAL_REQUIRED_WORKSPACE": {
        "summary": "APPROVAL_REQUIRED",
        "description": "Returned when the campaign is a playbook; its gifts go through the approval queue.",
        "value": {
          "error": "Always-on campaigns send gifts only through approval.",
          "code": "APPROVAL_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/",
          "retryable": false
        }
      },
      "ARTWORK_EMPTY": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when no file bytes.",
        "value": {
          "error": "Choose an artwork file.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "ARTWORK_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when no such asset in the workspace.",
        "value": {
          "error": "Artwork not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "ARTWORK_NOT_READY": {
        "summary": "ARTWORK_NOT_READY",
        "description": "Returned when file storage is unavailable.",
        "value": {
          "error": "Private artwork storage is unavailable.",
          "code": "ARTWORK_NOT_READY",
          "nextAction": "reread_and_retry",
          "retryable": false
        }
      },
      "ARTWORK_NOT_READY_WORKSPACE_READ": {
        "summary": "ARTWORK_NOT_READY",
        "description": "Returned when file storage is unavailable.",
        "value": {
          "error": "Private artwork storage is unavailable.",
          "code": "ARTWORK_NOT_READY",
          "nextAction": "retry_later",
          "retryable": true,
          "retryAfterMs": 30000
        }
      },
      "ARTWORK_QUOTA": {
        "summary": "ARTWORK_QUOTA",
        "description": "Returned when the workspace's file or daily upload allowance is used up.",
        "value": {
          "error": "Workspace artwork allowance reached. Contact support.",
          "code": "ARTWORK_QUOTA",
          "nextAction": "retry_later",
          "retryable": true,
          "retryAfterMs": 30000
        }
      },
      "ARTWORK_RATE_LIMIT": {
        "summary": "RATE_LIMIT",
        "description": "Returned when more than 1,200 artwork reads or 600 artwork writes in the current minute; wait `retryAfterMs`.",
        "value": {
          "error": "Too many requests. Please try again shortly.",
          "code": "RATE_LIMIT",
          "nextAction": "retry_later",
          "retryable": true,
          "retryAfterMs": 42000
        }
      },
      "ARTWORK_SIGNATURE": {
        "summary": "ARTWORK_SIGNATURE",
        "description": "Returned when the bytes are not the declared format.",
        "value": {
          "error": "File content does not match its declared format.",
          "code": "ARTWORK_SIGNATURE",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "ARTWORK_TOO_LARGE": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the file is larger than 5 MiB.",
        "value": {
          "error": "Artwork must be 5 MiB or smaller.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "ARTWORK_TYPE": {
        "summary": "ARTWORK_TYPE",
        "description": "Returned when unsupported type, or a filename whose extension does not match.",
        "value": {
          "error": "Upload a PNG, JPEG, WebP or PDF with a matching filename and content type.",
          "code": "ARTWORK_TYPE",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "ARTWORK_UNAVAILABLE": {
        "summary": "ARTWORK_UNAVAILABLE",
        "description": "Returned when an `asset_` ID is not an uploaded file of this workspace.",
        "value": {
          "error": "Artwork is missing or does not belong to this workspace.",
          "code": "ARTWORK_UNAVAILABLE",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "AUTH_REQUIRED": {
        "summary": "AUTH_REQUIRED",
        "description": "Returned when no credentials, or an OAuth token on a route that only takes workspace keys.",
        "value": {
          "error": "Sign in to continue.",
          "code": "AUTH_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/guides/connect",
          "retryable": false
        }
      },
      "AUTO_APPROVE_NOT_ALWAYS_ON": {
        "summary": "NOT_ALWAYS_ON",
        "description": "Returned when the campaign is not a playbook.",
        "value": {
          "error": "Only always-on playbooks auto-approve gifts.",
          "code": "NOT_ALWAYS_ON",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "BALANCE_CHANGED": {
        "summary": "BALANCE_CHANGED",
        "description": "Returned when the balance moved during approval; re-read and retry.",
        "value": {
          "error": "The balance changed while approving. Try again.",
          "code": "BALANCE_CHANGED",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "BALANCE_FUNDED": {
        "summary": "BALANCE_FUNDED",
        "description": "Returned when the gift was paid from the balance.",
        "value": {
          "error": "This gift was already paid from your balance and needs no checkout.",
          "code": "BALANCE_FUNDED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "BILLING_RECOVERY_REQUIRED": {
        "summary": "BILLING_RECOVERY_REQUIRED",
        "description": "Returned when the checkout needs provider reconciliation first.",
        "value": {
          "error": "The original checkout is still being reconciled. Retry after its expiry.",
          "code": "BILLING_RECOVERY_REQUIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "BUDGET_CAP": {
        "summary": "BUDGET_CAP",
        "description": "Returned when the playbook's monthly budget cannot cover the gift.",
        "value": {
          "error": "This playbook has $12.00 left this month. Raise the monthly budget to approve more.",
          "code": "BUDGET_CAP",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/campaigns/cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e?edit=1",
          "retryable": false
        }
      },
      "BUDGET_EXCEEDED": {
        "summary": "BUDGET_EXCEEDED",
        "description": "Returned when the gift would exceed the campaign's budget or per-person limit.",
        "value": {
          "error": "Campaign budget would be exceeded.",
          "code": "BUDGET_EXCEEDED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CAMPAIGN_COMPLETED": {
        "summary": "CAMPAIGN_COMPLETED",
        "description": "Returned when the campaign is completed.",
        "value": {
          "error": "Completed campaigns cannot be edited.",
          "code": "CAMPAIGN_COMPLETED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CAMPAIGN_INACTIVE": {
        "summary": "CAMPAIGN_INACTIVE",
        "description": "Returned when the campaign is not active.",
        "value": {
          "error": "Campaign must be authorized and active.",
          "code": "CAMPAIGN_INACTIVE",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CAMPAIGN_INACTIVE_CHECKOUT": {
        "summary": "CAMPAIGN_INACTIVE",
        "description": "Returned when the campaign is not active.",
        "value": {
          "error": "Authorize and activate this campaign before checkout.",
          "code": "CAMPAIGN_INACTIVE",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CAMPAIGN_NOT_ACTIVE": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the campaign is not active.",
        "value": {
          "error": "Authorize and activate this campaign before launching.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "CAMPAIGN_PAYMENT_REQUIRED_WORKSPACE": {
        "summary": "CAMPAIGN_PAYMENT_REQUIRED",
        "description": "Returned when the campaign is paid at checkout first.",
        "value": {
          "error": "Complete checkout for this campaign before sending gifts.",
          "code": "CAMPAIGN_PAYMENT_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/",
          "retryable": false
        }
      },
      "CAMPAIGN_REQUIRED": {
        "summary": "CAMPAIGN_REQUIRED",
        "description": "Returned when no `campaignId`.",
        "value": {
          "error": "Choose or create a campaign before sending a gift.",
          "code": "CAMPAIGN_REQUIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CAPABILITY_RETIRED": {
        "summary": "CAPABILITY_RETIRED",
        "description": "Returned when always: the capability is retired.",
        "value": {
          "error": "Gift invitation email and reminders have been retired. Copy a private claim link or export gift links for your own outreach tools.",
          "code": "CAPABILITY_RETIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CHECKOUT_ALREADY_PAID": {
        "summary": "CHECKOUT_ALREADY_PAID",
        "description": "Returned when the checkout is paid.",
        "value": {
          "error": "This checkout was already paid. Its funded gifts can be launched.",
          "code": "CHECKOUT_ALREADY_PAID",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CHECKOUT_COUNT_EXCEEDED": {
        "summary": "COUNT_EXCEEDED",
        "description": "Returned when more people than `maxSends`.",
        "value": {
          "error": "Campaign send limit would be exceeded.",
          "code": "COUNT_EXCEEDED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CHECKOUT_IDEMPOTENCY_CONFLICT": {
        "summary": "IDEMPOTENCY_CONFLICT",
        "description": "Returned when the `idempotencyKey` was used for another campaign or version.",
        "value": {
          "error": "That idempotency key belongs to different checkout details.",
          "code": "IDEMPOTENCY_CONFLICT",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "CHECKOUT_LOCKED": {
        "summary": "CHECKOUT_LOCKED",
        "description": "Returned when a checkout is open or paid for this campaign; wait or have a person cancel it.",
        "value": {
          "error": "Finish or cancel the current checkout before editing this campaign.",
          "code": "CHECKOUT_LOCKED",
          "nextAction": "retry_later",
          "retryable": true,
          "retryAfterMs": 60000
        }
      },
      "CHECKOUT_LOCKED_BUY": {
        "summary": "CHECKOUT_LOCKED",
        "description": "Returned when another checkout is open or paid.",
        "value": {
          "error": "This campaign already has a checkout. Resume or cancel it before buying again.",
          "code": "CHECKOUT_LOCKED",
          "nextAction": "retry_later",
          "retryable": true,
          "retryAfterMs": 60000
        }
      },
      "CHECKOUT_NOT_FOUND": {
        "summary": "CHECKOUT_NOT_FOUND",
        "description": "Returned when no such checkout in the workspace.",
        "value": {
          "error": "Checkout not found.",
          "code": "CHECKOUT_NOT_FOUND",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CHECKOUT_POLICY_CHANGED": {
        "summary": "POLICY_CHANGED",
        "description": "Returned when `expectedPolicyVersion` is stale.",
        "value": {
          "error": "Campaign changed. Review it before checkout.",
          "code": "POLICY_CHANGED",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "CHECKOUT_REQUIRED": {
        "summary": "CHECKOUT_REQUIRED",
        "description": "Returned when the playbook is paid at checkout.",
        "value": {
          "error": "This campaign is paid at checkout, not from the balance.",
          "code": "CHECKOUT_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/campaigns/cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e?review=1",
          "retryable": false
        }
      },
      "COLUMNS_IMPORT_INCOMPLETE": {
        "summary": "IMPORT_INCOMPLETE",
        "description": "Returned when the import is missing rows.",
        "value": {
          "error": "Finish saving the original rows before removing source columns.",
          "code": "IMPORT_INCOMPLETE",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "COLUMNS_SCOPE": {
        "summary": "INSUFFICIENT_SCOPE",
        "description": "Returned when an OAuth access token without `gifts:write`.",
        "value": {
          "error": "This connection cannot remove source columns.",
          "code": "INSUFFICIENT_SCOPE",
          "nextAction": "ask_user",
          "url": "https://gtmswag.com/guides/connect",
          "retryable": false
        }
      },
      "COUNT_EXCEEDED": {
        "summary": "COUNT_EXCEEDED",
        "description": "Returned when the campaign reached `maxSends`.",
        "value": {
          "error": "Campaign send limit reached.",
          "code": "COUNT_EXCEEDED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "CURSOR_STALE": {
        "summary": "CURSOR_STALE",
        "description": "Returned when the cursor is from before a campaign change, or invalid; start without `cursor`.",
        "value": {
          "error": "The selection changed. Start again from the first page.",
          "code": "CURSOR_STALE",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "CUSTOMIZATION_POLICY": {
        "summary": "CUSTOMIZATION_POLICY",
        "description": "Returned when the personalization differs from the approved one.",
        "value": {
          "error": "Gift personalization must match the approved campaign.",
          "code": "CUSTOMIZATION_POLICY",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "DELIVERY_NOT_RETRYABLE": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the delivery is not `dead`, or not this endpoint's.",
        "value": {
          "error": "Failed delivery not found or is already active.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "DEMO_LIMITED": {
        "summary": "DEMO_LIMITED",
        "description": "Returned when the workspace is a demo.",
        "value": {
          "error": "Sign up to upload artwork and photos. The demo workspace can't do this.",
          "code": "DEMO_LIMITED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "DUPLICATE_RECIPIENT": {
        "summary": "DUPLICATE_RECIPIENT",
        "description": "Returned when the same person appears twice in the request.",
        "value": {
          "error": "The list contains the same recipient more than once. Review duplicate source IDs, email or import rows.",
          "code": "DUPLICATE_RECIPIENT",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "DUPLICATE_SEND": {
        "summary": "DUPLICATE_SEND",
        "description": "Returned when the person or quote already has a gift.",
        "value": {
          "error": "This recipient or quote already has a send.",
          "code": "DUPLICATE_SEND",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "EXPORT_IMPORT_INCOMPLETE": {
        "summary": "IMPORT_INCOMPLETE",
        "description": "Returned when an import is missing rows for the `original` preset.",
        "value": {
          "error": "Finish saving the original import rows before exporting this list.",
          "code": "IMPORT_INCOMPLETE",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "EXPORT_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when the export does not exist or is older than 24 hours.",
        "value": {
          "error": "Export not found or expired. Generate a new export.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "FUNDED_CHECKOUT_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when not a live prepaid checkout of this workspace.",
        "value": {
          "error": "Funded checkout not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "FUNDING_REFUND_CONFLICT": {
        "summary": "FUNDING_REFUND_CONFLICT",
        "description": "Returned when the gift or checkout changed, or the gift is past the point of refund.",
        "value": {
          "error": "This gift or refund changed. Refresh and try again.",
          "code": "FUNDING_REFUND_CONFLICT",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "GIFT_LINK_CONFLICT": {
        "summary": "GIFT_LINK_CONFLICT",
        "description": "Returned when `generation` or `expectedMessageVersion` is stale, or the link is no longer unused; re-read the link.",
        "value": {
          "error": "This gift link changed. Refresh it before continuing.",
          "code": "GIFT_LINK_CONFLICT",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "GIFT_LINK_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when the gift has no private link in this workspace.",
        "value": {
          "error": "Gift link not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "GIFT_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when the gift or catalog product does not exist.",
        "value": {
          "error": "Gift not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "GIFT_RETIRED": {
        "summary": "GIFT_RETIRED",
        "description": "Returned when the gift is retired.",
        "value": {
          "error": "This gift is no longer available. Choose another gift.",
          "code": "GIFT_RETIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "GIFT_UNAVAILABLE": {
        "summary": "GIFT_UNAVAILABLE",
        "description": "Returned when the gift is unavailable or unpriced.",
        "value": {
          "error": "This gift is temporarily unavailable. Choose another gift.",
          "code": "GIFT_UNAVAILABLE",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "HUMAN_APPROVAL_REQUIRED": {
        "summary": "HUMAN_APPROVAL_REQUIRED",
        "description": "Returned when an API key or OAuth connection called a signed-in-person action; hand `url` to a person.",
        "value": {
          "error": "A signed-in person must approve this change.",
          "code": "HUMAN_APPROVAL_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/campaigns/cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e?review=1",
          "retryable": false
        }
      },
      "HUMAN_APPROVAL_REQUIRED_QUEUE": {
        "summary": "HUMAN_APPROVAL_REQUIRED",
        "description": "Returned when an API key or OAuth connection called a signed-in-person action; hand `url` to a person.",
        "value": {
          "error": "A signed-in person must approve this change.",
          "code": "HUMAN_APPROVAL_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
          "retryable": false
        }
      },
      "HUMAN_APPROVAL_REQUIRED_WORKSPACE": {
        "summary": "HUMAN_APPROVAL_REQUIRED",
        "description": "Returned when an API key or OAuth connection called a signed-in-person action; hand `url` to a person.",
        "value": {
          "error": "A signed-in person must approve this change.",
          "code": "HUMAN_APPROVAL_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/",
          "retryable": false
        }
      },
      "HUMAN_APPROVAL_REQUIRED_WORKSPACE_READ": {
        "summary": "HUMAN_APPROVAL_REQUIRED",
        "description": "Returned when an API key or OAuth connection called a signed-in-person action; hand `url` to a person.",
        "value": {
          "error": "A signed-in person must approve this change.",
          "code": "HUMAN_APPROVAL_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/",
          "retryable": false
        }
      },
      "IDEMPOTENCY_CONFLICT": {
        "summary": "IDEMPOTENCY_CONFLICT",
        "description": "Returned when the `idempotencyKey` was used with a different body.",
        "value": {
          "error": "This campaign request key was used with different content. Retry the original payload. Use a new key only for a separate intended campaign.",
          "code": "IDEMPOTENCY_CONFLICT",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "IMPORT_CONFLICT": {
        "summary": "IMPORT_CONFLICT",
        "description": "Returned when the `importId` was saved with different headers or columns.",
        "value": {
          "error": "This import already has different source columns. Start a new import or remove retained columns.",
          "code": "IMPORT_CONFLICT",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "IMPORT_INVALID": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when duplicate rows, positions or columns, or rows that do not fit the headers.",
        "value": {
          "error": "Import rows and positions must be unique.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "IMPORT_RECIPIENT_MISMATCH": {
        "summary": "IMPORT_RECIPIENT_MISMATCH",
        "description": "Returned when a row's `recipientId` or import IDs do not match the roster.",
        "value": {
          "error": "Source row does not match this campaign recipient.",
          "code": "IMPORT_RECIPIENT_MISMATCH",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "IMPORT_ROW_LIMIT": {
        "summary": "IMPORT_ROW_LIMIT",
        "description": "Returned when more than 500 retained rows.",
        "value": {
          "error": "Retain at most 500 source rows per campaign. Create another reviewed campaign.",
          "code": "IMPORT_ROW_LIMIT",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "IMPORT_SCOPE": {
        "summary": "INSUFFICIENT_SCOPE",
        "description": "Returned when an OAuth access token without `gifts:write`.",
        "value": {
          "error": "This connection cannot save source imports.",
          "code": "INSUFFICIENT_SCOPE",
          "nextAction": "ask_user",
          "url": "https://gtmswag.com/guides/connect",
          "retryable": false
        }
      },
      "IMPORT_SIZE_LIMIT": {
        "summary": "IMPORT_SIZE_LIMIT",
        "description": "Returned when the source is larger than 5 MiB.",
        "value": {
          "error": "Source CSV exceeds 5 MiB.",
          "code": "IMPORT_SIZE_LIMIT",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "INSUFFICIENT_BALANCE": {
        "summary": "INSUFFICIENT_BALANCE",
        "description": "Returned when the balance cannot cover the gift; a person adds funds at `url`.",
        "value": {
          "error": "Add funds to approve this gift. It costs $33.00.",
          "code": "INSUFFICIENT_BALANCE",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/settings?tab=billing",
          "retryable": false
        }
      },
      "INVALID_BILLING_CURSOR": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when `before` is not a checkout `cursor`.",
        "value": {
          "error": "Invalid billing history cursor.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "INVALID_CURSOR": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when `cursor` is not a cursor this route returned.",
        "value": {
          "error": "Invalid cursor.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "INVALID_JSON": {
        "summary": "INVALID_JSON",
        "description": "Returned when the body is not valid JSON.",
        "value": {
          "error": "Invalid JSON request.",
          "code": "INVALID_JSON",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "INVALID_KEY": {
        "summary": "AUTH_REQUIRED",
        "description": "Returned when the key is malformed, unknown or revoked.",
        "value": {
          "error": "Invalid or revoked API key.",
          "code": "AUTH_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/guides/connect",
          "retryable": false
        }
      },
      "INVITATION_CLOSED": {
        "summary": "INVITATION_CLOSED",
        "description": "Returned when the invitation is no longer pending.",
        "value": {
          "error": "This invitation has already been accepted or revoked.",
          "code": "INVITATION_CLOSED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "INVITATION_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when no such invitation.",
        "value": {
          "error": "Invitation not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "INVITE_RATE_LIMIT": {
        "summary": "RATE_LIMIT",
        "description": "Returned when more than 20 invitations an hour.",
        "value": {
          "error": "Too many requests. Please try again shortly.",
          "code": "RATE_LIMIT",
          "nextAction": "retry_later",
          "retryable": true,
          "retryAfterMs": 1800000
        }
      },
      "JSON_REQUIRED": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when a write with a body that is not `Content-Type: application/json` (a key request with no body needs no Content-Type).",
        "value": {
          "error": "Use application/json.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "LIMITS_BELOW_COMMITMENTS": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when new limits are below what is already spent or sent.",
        "value": {
          "error": "Limits cannot be lower than existing commitments.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "LINKS_SCOPE": {
        "summary": "INSUFFICIENT_SCOPE",
        "description": "Returned when an OAuth access token without `gifts:links:read`.",
        "value": {
          "error": "Reconnect with permission to retrieve private gift links and exports.",
          "code": "INSUFFICIENT_SCOPE",
          "nextAction": "ask_user",
          "url": "https://gtmswag.com/guides/connect",
          "retryable": false
        }
      },
      "LIVE_ADDRESSLESS_UNAVAILABLE": {
        "summary": "LIVE_ADDRESSLESS_UNAVAILABLE",
        "description": "Returned when a live gift without a sender-supplied US address (`addressMode:\"confirm\"`).",
        "value": {
          "error": "A shipping address supplied by the sender is required.",
          "code": "LIVE_ADDRESSLESS_UNAVAILABLE",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "LIVE_NOT_READY": {
        "summary": "LIVE_NOT_READY",
        "description": "Returned when the workspace is not live, or its email is unverified.",
        "value": {
          "error": "This workspace is not ready to order gifts yet.",
          "code": "LIVE_NOT_READY",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "LIVE_STATUS_PROTECTED": {
        "summary": "LIVE_STATUS_PROTECTED",
        "description": "Returned when a status change on a live gift.",
        "value": {
          "error": "Fulfillment status is managed by operations.",
          "code": "LIVE_STATUS_PROTECTED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "LOGO_TYPE": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the branding logo is a PDF or unknown asset.",
        "value": {
          "error": "Choose a PNG, JPG or WebP logo for the gift link.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "MEMBER_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when no such member.",
        "value": {
          "error": "Member not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "MESSAGE_POLICY": {
        "summary": "MESSAGE_POLICY",
        "description": "Returned when the note differs from the approved one.",
        "value": {
          "error": "The note must match the approved campaign message.",
          "code": "MESSAGE_POLICY",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "MESSAGE_TOO_LONG": {
        "summary": "MESSAGE_TOO_LONG",
        "description": "Returned when a note or welcome is over 500 characters after personalization.",
        "value": {
          "error": "Shorten the message for Jamie Chen to 500 characters, including names and companies.",
          "code": "MESSAGE_TOO_LONG",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "MODE_CHANGED": {
        "summary": "MODE_CHANGED",
        "description": "Returned when the workspace mode changed since the quote.",
        "value": {
          "error": "This quote is out of date. Request a new quote.",
          "code": "MODE_CHANGED",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "MODE_LOCKED": {
        "summary": "MODE_LOCKED",
        "description": "Returned when a checkout-paid campaign cannot become a playbook.",
        "value": {
          "error": "This campaign is paid at checkout and cannot become always-on. Create a new playbook instead.",
          "code": "MODE_LOCKED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "MONTHLY_BUDGET_REQUIRED": {
        "summary": "MONTHLY_BUDGET_REQUIRED",
        "description": "Returned when turning auto-approve on without a monthly budget.",
        "value": {
          "error": "Set a monthly budget to turn on auto-approve.",
          "code": "MONTHLY_BUDGET_REQUIRED",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "NO_NEW_RECIPIENTS": {
        "summary": "NO_NEW_RECIPIENTS",
        "description": "Returned when everyone already has a gift.",
        "value": {
          "error": "Every recipient already has a send. Add new recipients before checkout.",
          "code": "NO_NEW_RECIPIENTS",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "NO_PORTRAIT": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the gift has no portrait to review.",
        "value": {
          "error": "This gift does not use a recipient portrait.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "NOT_ALWAYS_ON": {
        "summary": "NOT_ALWAYS_ON",
        "description": "Returned when the campaign is a batch or single campaign, not a playbook.",
        "value": {
          "error": "Only always-on playbooks take people one at a time. Use add_recipients for this campaign.",
          "code": "NOT_ALWAYS_ON",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when no campaign or playbook with this ID in the workspace.",
        "value": {
          "error": "Campaign not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "NOTHING_TO_CHANGE": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when neither `message` nor `branding` was sent.",
        "value": {
          "error": "Change the message or sender details before saving.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "ORDER_CONFLICT": {
        "summary": "ORDER_CONFLICT",
        "description": "Returned when a gift is not awaiting payment.",
        "value": {
          "error": "Order changed or is not ready for this action. Refresh and retry.",
          "code": "ORDER_CONFLICT",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "ORDER_IDEMPOTENCY_CONFLICT": {
        "summary": "IDEMPOTENCY_CONFLICT",
        "description": "Returned when the `idempotencyKey` was used for other gifts.",
        "value": {
          "error": "Checkout key already used for different gifts.",
          "code": "IDEMPOTENCY_CONFLICT",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "OUTCOME_IDEMPOTENCY_CONFLICT": {
        "summary": "IDEMPOTENCY_CONFLICT",
        "description": "Returned when the same `source` + `externalEventId` with different details.",
        "value": {
          "error": "External event ID was used for different details.",
          "code": "IDEMPOTENCY_CONFLICT",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "OWNER_REQUIRED": {
        "summary": "OWNER_REQUIRED",
        "description": "Returned when the target is the workspace owner.",
        "value": {
          "error": "The workspace owner cannot be removed.",
          "code": "OWNER_REQUIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "OWNER_ROLE_FIXED": {
        "summary": "OWNER_REQUIRED",
        "description": "Returned when the target is the owner.",
        "value": {
          "error": "The workspace owner's role cannot be changed.",
          "code": "OWNER_REQUIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "PAYMENT_UNAVAILABLE": {
        "summary": "PAYMENT_UNAVAILABLE",
        "description": "Returned when the payment page could not be created.",
        "value": {
          "error": "Payment could not be started. Try again.",
          "code": "PAYMENT_UNAVAILABLE",
          "nextAction": "reread_and_retry",
          "retryable": false
        }
      },
      "PERSONALIZATION_REQUIRED": {
        "summary": "PERSONALIZATION_REQUIRED",
        "description": "Returned when `customization.displayText` is missing or outside the gift's limits.",
        "value": {
          "error": "Add bottle engraving before approving this gift.",
          "code": "PERSONALIZATION_REQUIRED",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "PHOTO_CHANGED": {
        "summary": "PHOTO_CHANGED",
        "description": "Returned when `version` is stale; re-read the gift.",
        "value": {
          "error": "Photo changed. Refresh and check the current image.",
          "code": "PHOTO_CHANGED",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "PHOTO_DOWNLOAD": {
        "summary": "PHOTO_DOWNLOAD",
        "description": "Returned when the download failed.",
        "value": {
          "error": "The photo could not be downloaded. Try again, or upload it directly.",
          "code": "PHOTO_DOWNLOAD",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "PHOTO_LOCKED": {
        "summary": "PHOTO_LOCKED",
        "description": "Returned when fulfillment locked the photo.",
        "value": {
          "error": "The photo is locked after order review. Contact Better Swag before changing approved production details.",
          "code": "PHOTO_LOCKED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "PHOTO_TYPE": {
        "summary": "PHOTO_TYPE",
        "description": "Returned when the URL is not a direct image.",
        "value": {
          "error": "This link is not a PNG, JPEG or WebP image. Use a direct image URL, not a profile or sharing page.",
          "code": "PHOTO_TYPE",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "PHOTO_URL": {
        "summary": "PHOTO_URL",
        "description": "Returned when the URL is not public HTTPS.",
        "value": {
          "error": "Use a direct, public HTTPS photo URL. Private or local links cannot be imported.",
          "code": "PHOTO_URL",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "PLAYBOOK_BUSY": {
        "summary": "PLAYBOOK_BUSY",
        "description": "Returned when concurrent adds to the same playbook; wait `retryAfterMs` (under a second) and send the same call.",
        "value": {
          "error": "Other people are being added to this playbook right now. Try again in a moment.",
          "code": "PLAYBOOK_BUSY",
          "nextAction": "retry_later",
          "retryable": true,
          "retryAfterMs": 600
        }
      },
      "PLAYBOOK_OFF": {
        "summary": "PLAYBOOK_OFF",
        "description": "Returned when the playbook is a draft or paused; hand `url` to a person to turn it on.",
        "value": {
          "error": "Turn this playbook on to add people.",
          "code": "PLAYBOOK_OFF",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/campaigns/cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e?review=1",
          "retryable": false
        }
      },
      "POLICY_CHANGED": {
        "summary": "POLICY_CHANGED",
        "description": "Returned when `expectedPolicyVersion` is stale; re-read the campaign and retry.",
        "value": {
          "error": "This campaign changed. Refresh before saving your edits.",
          "code": "POLICY_CHANGED",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "POLICY_VIOLATION": {
        "summary": "POLICY_VIOLATION",
        "description": "Returned when the gift or sender differs from the approved campaign.",
        "value": {
          "error": "Gift is outside the approved campaign.",
          "code": "POLICY_VIOLATION",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "PORTRAIT_IMAGE_REQUIRED": {
        "summary": "PORTRAIT_IMAGE_REQUIRED",
        "description": "Returned when a portrait that is not a PNG, JPEG or WebP image.",
        "value": {
          "error": "A recipient photo must be a PNG, JPEG or WebP image, not a logo PDF.",
          "code": "PORTRAIT_IMAGE_REQUIRED",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "PORTRAIT_REQUIRED": {
        "summary": "PORTRAIT_REQUIRED",
        "description": "Returned when the gift prints a portrait and the person has no photo.",
        "value": {
          "error": "Add a photo or a LinkedIn sourcing request for Jamie Chen. Shared logos do not replace their portrait.",
          "code": "PORTRAIT_REQUIRED",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "PORTRAIT_RESOLUTION": {
        "summary": "PORTRAIT_RESOLUTION",
        "description": "Returned when a portrait smaller than 256 × 256 or larger than 40 megapixels.",
        "value": {
          "error": "Choose a clear image at least 256 × 256 pixels and no larger than 40 megapixels. Re-export the image if its dimensions cannot be read.",
          "code": "PORTRAIT_RESOLUTION",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "PREPAID_DISABLED": {
        "summary": "PREPAID_DISABLED",
        "description": "Returned when live prepaid checkout is not enabled.",
        "value": {
          "error": "Prepaid gift checkout is unavailable.",
          "code": "PREPAID_DISABLED",
          "nextAction": "reread_and_retry",
          "retryable": false
        }
      },
      "PREVIEW_IMAGES_ONLY": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when `preview=1` on a PDF.",
        "value": {
          "error": "Only images can be previewed.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "PRICE_QUOTE_REQUIRED": {
        "summary": "PRICE_QUOTE_REQUIRED",
        "description": "Returned when the gift's price still needs a supplier quote.",
        "value": {
          "error": "This gift is temporarily unavailable. Choose another gift.",
          "code": "PRICE_QUOTE_REQUIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "QUEUE_NOT_ALWAYS_ON": {
        "summary": "NOT_ALWAYS_ON",
        "description": "Returned when the campaign is not a playbook.",
        "value": {
          "error": "Only always-on campaigns approve from the queue.",
          "code": "NOT_ALWAYS_ON",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "QUEUE_PLAYBOOK_OFF": {
        "summary": "PLAYBOOK_OFF",
        "description": "Returned when the playbook is a draft or paused.",
        "value": {
          "error": "Turn the playbook on before approving gifts.",
          "code": "PLAYBOOK_OFF",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/campaigns/cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e?review=1",
          "retryable": false
        }
      },
      "QUOTE_CHANGED": {
        "summary": "QUOTE_CHANGED",
        "description": "Returned when the details differ from the quote or the paid checkout.",
        "value": {
          "error": "Gift details changed. Request a fresh quote.",
          "code": "QUOTE_CHANGED",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "QUOTE_EXPIRED": {
        "summary": "QUOTE_EXPIRED",
        "description": "Returned when the quote is older than 15 minutes.",
        "value": {
          "error": "Quote expired. Request a fresh quote.",
          "code": "QUOTE_EXPIRED",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "QUOTE_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when no quote with this `quoteId`.",
        "value": {
          "error": "Quote not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "RATE_LIMIT": {
        "summary": "RATE_LIMIT",
        "description": "Returned when more than 240 requests in the current minute for this workspace (REST and MCP share the limit); wait `retryAfterMs`.",
        "value": {
          "error": "Too many requests. Please try again shortly.",
          "code": "RATE_LIMIT",
          "nextAction": "retry_later",
          "retryable": true,
          "retryAfterMs": 42000
        }
      },
      "RECIPIENT_ALREADY_SENT": {
        "summary": "RECIPIENT_ALREADY_SENT",
        "description": "Returned when a selected person already has a gift.",
        "value": {
          "error": "Recipients with existing gifts cannot be removed or have their printed notes changed. Select only unsent recipients.",
          "code": "RECIPIENT_ALREADY_SENT",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "RECIPIENT_IDENTITY_CONFLICT": {
        "summary": "RECIPIENT_IDENTITY_CONFLICT",
        "description": "Returned when the source IDs or email match a different existing person.",
        "value": {
          "error": "Recipient identity conflicts with an existing person. Review the matching record and use its recipient ID.",
          "code": "RECIPIENT_IDENTITY_CONFLICT",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "RECIPIENT_LIMIT": {
        "summary": "RECIPIENT_LIMIT",
        "description": "Returned when the playbook already holds 2,000 people.",
        "value": {
          "error": "A playbook holds up to 2000 people. Start another playbook for more.",
          "code": "RECIPIENT_LIMIT",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "RECIPIENT_NOT_FOUND": {
        "summary": "RECIPIENT_NOT_FOUND",
        "description": "Returned when no such person on the playbook.",
        "value": {
          "error": "That person is not in this campaign.",
          "code": "RECIPIENT_NOT_FOUND",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "RECIPIENT_SCOPE": {
        "summary": "RECIPIENT_SCOPE",
        "description": "Returned when a `recipientId` is not a person of this workspace.",
        "value": {
          "error": "Recipient not found in this workspace.",
          "code": "RECIPIENT_SCOPE",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "RECIPIENT_SELECTION": {
        "summary": "RECIPIENT_SCOPE",
        "description": "Returned when nothing selected, an ID not on the roster, or an email matching zero or several people.",
        "value": {
          "error": "Select recipients from this campaign.",
          "code": "RECIPIENT_SCOPE",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "RECIPIENT_SKIPPED": {
        "summary": "RECIPIENT_SKIPPED",
        "description": "Returned when a person skipped them.",
        "value": {
          "error": "That person was skipped. Undo the skip from Home to gift them.",
          "code": "RECIPIENT_SKIPPED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
          "retryable": false
        }
      },
      "REFUND_CONFLICT": {
        "summary": "GIFT_LINK_CONFLICT",
        "description": "Returned when `generation` is stale.",
        "value": {
          "error": "This invitation changed. Refresh and try again.",
          "code": "GIFT_LINK_CONFLICT",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "REFUND_UNUSED_ONLY": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the gift is unpaid, claimed or already refunded.",
        "value": {
          "error": "Only unused paid gifts can be requested for a refund.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "REGIFT_PRIVATE_LINK": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the new recipient is not `addressMode:\"confirm\"`.",
        "value": {
          "error": "Use a private link for the replacement recipient.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "REPEAT_REVIEW_CHECKOUT": {
        "summary": "REPEAT_REVIEW_REQUIRED",
        "description": "Returned when unapproved repeat recipients.",
        "value": {
          "error": "Review and approve repeat recipients before checkout.",
          "code": "REPEAT_REVIEW_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/campaigns/cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e?review=1",
          "retryable": false
        }
      },
      "REPEAT_REVIEW_REQUIRED_QUEUE": {
        "summary": "REPEAT_REVIEW_REQUIRED",
        "description": "Returned when already gifted by another campaign; approve with `approveRepeat:true`.",
        "value": {
          "error": "This person already received a gift from another campaign. Approve the repeat to send another.",
          "code": "REPEAT_REVIEW_REQUIRED",
          "nextAction": "open_url",
          "url": "https://gtmswag.com/?queue=cmp_4f9c2a7e1b3d5f6a8c0e2d4b6a8f0c1e",
          "retryable": false
        }
      },
      "REPEAT_SELECTION": {
        "summary": "RECIPIENT_SCOPE",
        "description": "Returned when a person is not on the repeat list, or an email is ambiguous.",
        "value": {
          "error": "Select a repeated recipient by ID.",
          "code": "RECIPIENT_SCOPE",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "REQUEST_TOO_LARGE": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the body exceeds 1 MiB.",
        "value": {
          "error": "Request is too large.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "ROSTER_SCOPE": {
        "summary": "RECIPIENT_SCOPE",
        "description": "Returned when the recipient differs from the approved roster.",
        "value": {
          "error": "Recipient details are outside the approved roster.",
          "code": "RECIPIENT_SCOPE",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "SANDBOX_CHECKOUT_DISABLED": {
        "summary": "SANDBOX_CHECKOUT_DISABLED",
        "description": "Returned when test checkout is not enabled.",
        "value": {
          "error": "Checkout is unavailable.",
          "code": "SANDBOX_CHECKOUT_DISABLED",
          "nextAction": "reread_and_retry",
          "retryable": false
        }
      },
      "SELECTION_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when a selected `recipientIds` or `giftIds` entry is not in the campaign.",
        "value": {
          "error": "A selected recipient or gift is not in this campaign.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "SEND_CHANGED": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the gift changed during the update.",
        "value": {
          "error": "Send changed. Refresh and retry.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "SEND_IDEMPOTENCY_CONFLICT": {
        "summary": "IDEMPOTENCY_CONFLICT",
        "description": "Returned when the `idempotencyKey` was used with different details.",
        "value": {
          "error": "That idempotency key was used for different gift details.",
          "code": "IDEMPOTENCY_CONFLICT",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "SEND_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when no gift with this ID in the workspace.",
        "value": {
          "error": "Send not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "SOURCE_IMPORT_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when no import with this `importId` in the campaign.",
        "value": {
          "error": "Source import not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "STATUS_CHANGE_UNAVAILABLE": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the status cannot move to that step.",
        "value": {
          "error": "That status change is not available.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "STRIPE_EVIDENCE_INVALID": {
        "summary": "STRIPE_EVIDENCE_INVALID",
        "description": "Returned when Stripe's records do not match the checkout.",
        "value": {
          "error": "Stripe checkout evidence does not match this campaign.",
          "code": "STRIPE_EVIDENCE_INVALID",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "STRIPE_UNAVAILABLE": {
        "summary": "STRIPE_UNAVAILABLE",
        "description": "Returned when the payment provider failed or is not configured.",
        "value": {
          "error": "Stripe is unavailable. Retry this same operation.",
          "code": "STRIPE_UNAVAILABLE",
          "nextAction": "reread_and_retry",
          "retryable": false
        }
      },
      "TEAM_CHANGED": {
        "summary": "TEAM_CHANGED",
        "description": "Returned when membership changed during the request.",
        "value": {
          "error": "The workspace changed. Refresh the members list and try again.",
          "code": "TEAM_CHANGED",
          "nextAction": "reread_and_retry",
          "retryable": true
        }
      },
      "TEAM_MANAGER_REQUIRED": {
        "summary": "TEAM_MANAGER_REQUIRED",
        "description": "Returned when the key's member (or the signed-in person) is not an owner or admin.",
        "value": {
          "error": "A workspace owner or admin must make this change.",
          "code": "TEAM_MANAGER_REQUIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "TEAM_OWNER_REQUIRED": {
        "summary": "TEAM_OWNER_REQUIRED",
        "description": "Returned when only the owner may grant, change or remove admin access.",
        "value": {
          "error": "Only the workspace owner can manage admins.",
          "code": "TEAM_OWNER_REQUIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "TOO_MANY_ARTWORK_FILES": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when a recipient would carry more than five artwork files.",
        "value": {
          "error": "Use up to five artwork files per recipient, including the logo.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "UPLOAD_CAPACITY": {
        "summary": "UPLOAD_CAPACITY",
        "description": "Returned when four unfinished uploads or 64 MiB declared.",
        "value": {
          "error": "This workspace has unfinished uploads. Finish them or wait for their six-hour expiry before starting another large upload.",
          "code": "UPLOAD_CAPACITY",
          "nextAction": "retry_later",
          "retryable": true,
          "retryAfterMs": 30000
        }
      },
      "UPLOAD_CONFLICT": {
        "summary": "UPLOAD_CONFLICT",
        "description": "Returned when the upload's metadata or a part's bytes differ from an earlier call.",
        "value": {
          "error": "This upload ID or part already contains different data. Retry the original part, or start a new upload.",
          "code": "UPLOAD_CONFLICT",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "UPLOAD_ENCODING_INVALID": {
        "summary": "UPLOAD_ENCODING_INVALID",
        "description": "Returned when a part is not canonical base64, or the assembled data is not UTF-8 JSON.",
        "value": {
          "error": "Upload parts must use canonical base64.",
          "code": "UPLOAD_ENCODING_INVALID",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "UPLOAD_EXPIRED": {
        "summary": "UPLOAD_EXPIRED",
        "description": "Returned when the upload is older than 6 hours.",
        "value": {
          "error": "This upload expired. Start the upload again with a new ID.",
          "code": "UPLOAD_EXPIRED",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "UPLOAD_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when the upload belongs to someone else or does not exist.",
        "value": {
          "error": "Upload not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "UPLOAD_SCOPE": {
        "summary": "INSUFFICIENT_SCOPE",
        "description": "Returned when an OAuth access token without `gifts:write`.",
        "value": {
          "error": "Grant permission to prepare gifts before uploading source data.",
          "code": "INSUFFICIENT_SCOPE",
          "nextAction": "ask_user",
          "url": "https://gtmswag.com/guides/connect",
          "retryable": false
        }
      },
      "UPLOAD_SIZE_MISMATCH": {
        "summary": "UPLOAD_SIZE_MISMATCH",
        "description": "Returned when the parts do not add up to `totalBytes`.",
        "value": {
          "error": "Uploaded part bytes do not match the declared total.",
          "code": "UPLOAD_SIZE_MISMATCH",
          "nextAction": "stop",
          "retryable": false
        }
      },
      "VALIDATION_ERROR_launchCampaign": {
        "summary": "VALIDATION_ERROR",
        "description": "Returned when the body or query fails its schema; `error` names each field.",
        "value": {
          "error": "cursor: Too big: expected number to be <=500",
          "code": "VALIDATION_ERROR",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "VALIDATION_ERROR_listBalanceLedger": {
        "summary": "VALIDATION_ERROR",
        "description": "Returned when the body or query fails its schema; `error` names each field.",
        "value": {
          "error": "limit: Too small: expected number to be >=1",
          "code": "VALIDATION_ERROR",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "VALIDATION_ERROR_listCampaigns": {
        "summary": "VALIDATION_ERROR",
        "description": "Returned when the body or query fails its schema; `error` names each field.",
        "value": {
          "error": "mode: Invalid option: expected one of \"always_on\"|\"batch\"|\"single\"",
          "code": "VALIDATION_ERROR",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "VALIDATION_ERROR_listQueue": {
        "summary": "VALIDATION_ERROR",
        "description": "Returned when the body or query fails its schema; `error` names each field.",
        "value": {
          "error": "campaignId: Too small: expected string to have >=1 characters",
          "code": "VALIDATION_ERROR",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "VALIDATION_ERROR_UNKNOWN_FIELD": {
        "summary": "VALIDATION_ERROR",
        "description": "Returned when the body or query fails its schema; `error` names each field.",
        "value": {
          "error": "Input: Unrecognized key: \"unexpected\"",
          "code": "VALIDATION_ERROR",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "WEBHOOK_NOT_FOUND": {
        "summary": "NOT_FOUND",
        "description": "Returned when no such active endpoint.",
        "value": {
          "error": "Webhook not found.",
          "code": "NOT_FOUND",
          "nextAction": "ask_user",
          "retryable": false
        }
      },
      "WEBHOOK_UNAVAILABLE": {
        "summary": "WEBHOOK_UNAVAILABLE",
        "description": "Returned when webhooks are not configured on this deployment.",
        "value": {
          "error": "Webhook encryption is not configured.",
          "code": "WEBHOOK_UNAVAILABLE",
          "nextAction": "reread_and_retry",
          "retryable": false
        }
      },
      "WEBHOOK_URL": {
        "summary": "INVALID_REQUEST",
        "description": "Returned when the URL is not public HTTPS on port 443.",
        "value": {
          "error": "Use a public HTTPS webhook URL.",
          "code": "INVALID_REQUEST",
          "nextAction": "ask_user",
          "retryable": false
        }
      }
    },
    "responses": {
      "ArtworkRateLimited": {
        "description": "Too many requests: `RATE_LIMIT`. more than 1,200 artwork reads or 600 artwork writes in the current minute; wait `retryAfterMs`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "ARTWORK_RATE_LIMIT": {
                "$ref": "#/components/examples/ARTWORK_RATE_LIMIT"
              }
            }
          }
        }
      },
      "BadRequestGiftLinkMessage": {
        "description": "Bad request: `VALIDATION_ERROR`, `INVALID_REQUEST`, `MESSAGE_TOO_LONG`, `INVALID_JSON`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "VALIDATION_ERROR": {
                "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
              },
              "NOTHING_TO_CHANGE": {
                "$ref": "#/components/examples/NOTHING_TO_CHANGE"
              },
              "MESSAGE_TOO_LONG": {
                "$ref": "#/components/examples/MESSAGE_TOO_LONG"
              },
              "INVALID_JSON": {
                "$ref": "#/components/examples/INVALID_JSON"
              }
            }
          }
        }
      },
      "BadRequestQueueFilter": {
        "description": "Bad request: `VALIDATION_ERROR`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "VALIDATION_ERROR": {
                "$ref": "#/components/examples/VALIDATION_ERROR_listQueue"
              }
            }
          }
        }
      },
      "BadRequestValidation": {
        "description": "Bad request: `VALIDATION_ERROR`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "VALIDATION_ERROR": {
                "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
              }
            }
          }
        }
      },
      "BadRequestValidationOrCursor": {
        "description": "Bad request: `VALIDATION_ERROR`, `INVALID_REQUEST`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "VALIDATION_ERROR": {
                "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
              },
              "INVALID_CURSOR": {
                "$ref": "#/components/examples/INVALID_CURSOR"
              }
            }
          }
        }
      },
      "BadRequestValidationOrJson": {
        "description": "Bad request: `VALIDATION_ERROR`, `INVALID_JSON`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "VALIDATION_ERROR": {
                "$ref": "#/components/examples/VALIDATION_ERROR_UNKNOWN_FIELD"
              },
              "INVALID_JSON": {
                "$ref": "#/components/examples/INVALID_JSON"
              }
            }
          }
        }
      },
      "ConflictGiftCheckout": {
        "description": "Conflict: `BALANCE_FUNDED`, `IDEMPOTENCY_CONFLICT`, `ORDER_CONFLICT`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "BALANCE_FUNDED": {
                "$ref": "#/components/examples/BALANCE_FUNDED"
              },
              "ORDER_IDEMPOTENCY_CONFLICT": {
                "$ref": "#/components/examples/ORDER_IDEMPOTENCY_CONFLICT"
              },
              "ORDER_CONFLICT": {
                "$ref": "#/components/examples/ORDER_CONFLICT"
              }
            }
          }
        }
      },
      "ConflictGiftLink": {
        "description": "Conflict: `GIFT_LINK_CONFLICT`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "GIFT_LINK_CONFLICT": {
                "$ref": "#/components/examples/GIFT_LINK_CONFLICT"
              }
            }
          }
        }
      },
      "ForbiddenArtwork": {
        "description": "Forbidden: `ARTWORK_UNAVAILABLE`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "ARTWORK_UNAVAILABLE": {
                "$ref": "#/components/examples/ARTWORK_UNAVAILABLE"
              }
            }
          }
        }
      },
      "ForbiddenArtworkOrRecipientScope": {
        "description": "Forbidden: `ARTWORK_UNAVAILABLE`, `RECIPIENT_SCOPE`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "ARTWORK_UNAVAILABLE": {
                "$ref": "#/components/examples/ARTWORK_UNAVAILABLE"
              },
              "RECIPIENT_SCOPE": {
                "$ref": "#/components/examples/RECIPIENT_SCOPE"
              }
            }
          }
        }
      },
      "ForbiddenDemo": {
        "description": "Forbidden: `DEMO_LIMITED`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "DEMO_LIMITED": {
                "$ref": "#/components/examples/DEMO_LIMITED"
              }
            }
          }
        }
      },
      "ForbiddenHumanOnly": {
        "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "HUMAN_APPROVAL_REQUIRED": {
                "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED"
              }
            }
          }
        }
      },
      "ForbiddenHumanOnlyOrManager": {
        "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "HUMAN_APPROVAL_REQUIRED": {
                "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED"
              },
              "TEAM_MANAGER_REQUIRED": {
                "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
              }
            }
          }
        }
      },
      "ForbiddenHumanOnlyOrManagerQueue": {
        "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "HUMAN_APPROVAL_REQUIRED": {
                "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_QUEUE"
              },
              "TEAM_MANAGER_REQUIRED": {
                "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
              }
            }
          }
        }
      },
      "ForbiddenHumanOnlyOrManagerWorkspace": {
        "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "HUMAN_APPROVAL_REQUIRED": {
                "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
              },
              "TEAM_MANAGER_REQUIRED": {
                "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
              }
            }
          }
        }
      },
      "ForbiddenLinksScope": {
        "description": "Forbidden: `INSUFFICIENT_SCOPE`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "LINKS_SCOPE": {
                "$ref": "#/components/examples/LINKS_SCOPE"
              }
            }
          }
        }
      },
      "ForbiddenLiveCheckout": {
        "description": "Forbidden: `HUMAN_APPROVAL_REQUIRED`, `TEAM_MANAGER_REQUIRED`, `LIVE_NOT_READY`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "HUMAN_APPROVAL_REQUIRED": {
                "$ref": "#/components/examples/HUMAN_APPROVAL_REQUIRED_WORKSPACE"
              },
              "TEAM_MANAGER_REQUIRED": {
                "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
              },
              "LIVE_NOT_READY": {
                "$ref": "#/components/examples/LIVE_NOT_READY"
              }
            }
          }
        }
      },
      "ForbiddenManager": {
        "description": "Forbidden: `TEAM_MANAGER_REQUIRED`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "TEAM_MANAGER_REQUIRED": {
                "$ref": "#/components/examples/TEAM_MANAGER_REQUIRED"
              }
            }
          }
        }
      },
      "GoneCapabilityRetired": {
        "description": "Gone: `CAPABILITY_RETIRED`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "CAPABILITY_RETIRED": {
                "$ref": "#/components/examples/CAPABILITY_RETIRED"
              }
            }
          }
        }
      },
      "JsonRequired": {
        "description": "Unsupported media type: `INVALID_REQUEST`. a write with a body that is not `Content-Type: application/json` (a key request with no body needs no Content-Type).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "JSON_REQUIRED": {
                "$ref": "#/components/examples/JSON_REQUIRED"
              }
            }
          }
        }
      },
      "NotFoundCampaign": {
        "description": "Not found: `NOT_FOUND`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "NOT_FOUND": {
                "$ref": "#/components/examples/NOT_FOUND"
              }
            }
          }
        }
      },
      "NotFoundCampaignOrRecipient": {
        "description": "Not found: `NOT_FOUND`, `RECIPIENT_NOT_FOUND`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "NOT_FOUND": {
                "$ref": "#/components/examples/NOT_FOUND"
              },
              "RECIPIENT_NOT_FOUND": {
                "$ref": "#/components/examples/RECIPIENT_NOT_FOUND"
              }
            }
          }
        }
      },
      "NotFoundCheckout": {
        "description": "Not found: `CHECKOUT_NOT_FOUND`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "CHECKOUT_NOT_FOUND": {
                "$ref": "#/components/examples/CHECKOUT_NOT_FOUND"
              }
            }
          }
        }
      },
      "NotFoundGift": {
        "description": "Not found: `NOT_FOUND`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "GIFT_NOT_FOUND": {
                "$ref": "#/components/examples/GIFT_NOT_FOUND"
              }
            }
          }
        }
      },
      "NotFoundGiftLink": {
        "description": "Not found: `NOT_FOUND`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "GIFT_LINK_NOT_FOUND": {
                "$ref": "#/components/examples/GIFT_LINK_NOT_FOUND"
              }
            }
          }
        }
      },
      "NotFoundMember": {
        "description": "Not found: `NOT_FOUND`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "MEMBER_NOT_FOUND": {
                "$ref": "#/components/examples/MEMBER_NOT_FOUND"
              }
            }
          }
        }
      },
      "NotFoundSend": {
        "description": "Not found: `NOT_FOUND`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "SEND_NOT_FOUND": {
                "$ref": "#/components/examples/SEND_NOT_FOUND"
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests: `RATE_LIMIT`. more than 240 requests in the current minute for this workspace (REST and MCP share the limit); wait `retryAfterMs`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "RATE_LIMIT": {
                "$ref": "#/components/examples/RATE_LIMIT"
              }
            }
          }
        }
      },
      "RequestTooLarge": {
        "description": "Request too large: `INVALID_REQUEST`. the body exceeds 1 MiB.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "REQUEST_TOO_LARGE": {
                "$ref": "#/components/examples/REQUEST_TOO_LARGE"
              }
            }
          }
        }
      },
      "TooManyRequestsArtwork": {
        "description": "Too many requests: `ARTWORK_QUOTA`, `RATE_LIMIT`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "ARTWORK_QUOTA": {
                "$ref": "#/components/examples/ARTWORK_QUOTA"
              },
              "ARTWORK_RATE_LIMIT": {
                "$ref": "#/components/examples/ARTWORK_RATE_LIMIT"
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Not authenticated: `AUTH_REQUIRED`. no credentials, or an OAuth token on a route that only takes workspace keys; the key is malformed, unknown or revoked.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "AUTH_REQUIRED": {
                "$ref": "#/components/examples/AUTH_REQUIRED"
              },
              "INVALID_KEY": {
                "$ref": "#/components/examples/INVALID_KEY"
              }
            }
          }
        }
      },
      "UnavailableStripe": {
        "description": "Unavailable: `STRIPE_UNAVAILABLE`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "STRIPE_UNAVAILABLE": {
                "$ref": "#/components/examples/STRIPE_UNAVAILABLE"
              }
            }
          }
        }
      },
      "UnsupportedMediaTypeLogo": {
        "description": "Unsupported media type: `INVALID_REQUEST`. Each example says when.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "LOGO_TYPE": {
                "$ref": "#/components/examples/LOGO_TYPE"
              },
              "JSON_REQUIRED": {
                "$ref": "#/components/examples/JSON_REQUIRED"
              }
            }
          }
        }
      },
      "Error": {
        "description": "Any other refusal or failure, such as 403 CSRF (a cross-origin `Origin` header), 403 HTTPS_REQUIRED or 500 INTERNAL_ERROR, with what to do next.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "INTERNAL_ERROR": {
                "summary": "An unexpected failure",
                "value": {
                  "error": "Something went wrong. Try again later or contact support.",
                  "code": "INTERNAL_ERROR",
                  "nextAction": "stop",
                  "retryable": false
                }
              }
            }
          }
        }
      }
    }
  }
}
