{
  "openapi": "3.1.0",
  "info": {
    "title": "BackstagePass API",
    "version": "1.0.0",
    "summary": "Access to one creator's own BackstagePass data, and the Followers tab's verbs for one person.",
    "description": "One key per creator account, scoped to that creator's own data. The People endpoints are the only writes: each does what Studio's Followers page does for one person, keyed by email. A Pass is named by its public id (pass_ plus 16 lowercase letters and digits); the integer id never appears. Responses are bare JSON objects (no envelope), except /api/v1/audience/export, which returns CSV. Generated from app/controllers/api/v1/*.rb."
  },
  "externalDocs": {
    "description": "Guides, webhook events and the agent steps",
    "url": "https://backstagepass.com/help/how/automations"
  },
  "servers": [
    {
      "url": "https://backstagepass.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "The creator the key belongs to."
    },
    {
      "name": "Audience",
      "description": "Your followers and imported contacts."
    },
    {
      "name": "Streams",
      "description": "Your ended lives and the notifications sent for them."
    },
    {
      "name": "Passes",
      "description": "Your Passes, by their public id."
    },
    {
      "name": "People",
      "description": "One person on your list, keyed by email: add, find, revoke, block and unblock."
    }
  ],
  "paths": {
    "/api/v1/me": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "Account"
        ],
        "summary": "Your creator profile",
        "description": "The creator the key belongs to.",
        "responses": {
          "200": {
            "description": "The creator profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                },
                "examples": {
                  "default": {
                    "value": {
                      "handle": "maya",
                      "display_name": "Maya Rivers",
                      "plan": "free"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/audience": {
      "get": {
        "operationId": "getAudience",
        "tags": [
          "Audience"
        ],
        "summary": "Your audience list, as counts",
        "description": "Aggregate counts only, no people. The reachable counts come from the same eligibility query the Followers page, the composer preview and the receipt use.",
        "responses": {
          "200": {
            "description": "Audience counts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Audience"
                },
                "examples": {
                  "default": {
                    "value": {
                      "fans": 1240,
                      "push_reachable": 610,
                      "email_reachable": 980,
                      "imported_awaiting_first_sign_in": 75,
                      "text_reachable": 0,
                      "imported": 300,
                      "imported_claimed": 120,
                      "generated_at": "2026-10-27T18:04:05Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/audience/export": {
      "get": {
        "operationId": "exportAudience",
        "tags": [
          "Audience"
        ],
        "summary": "The same CSV as Export on Followers",
        "description": "One row per person: every follower, then unclaimed imported contacts. Byte-identical to the Export button on the Followers page. The body starts with a UTF-8 byte order mark. Streamed: no Content-Length and no Content-Disposition header.",
        "responses": {
          "200": {
            "description": "CSV file. Header row = the columns listed in the schema description.",
            "content": {
              "text/csv; charset=utf-8": {
                "schema": {
                  "type": "string",
                  "description": "Columns, in order: name, email, phone, active_access, expired_access, active_names, expired_names, lifetime_spend, spend_passes, spend_tickets, spend_drops, eligible_lives, showed_up, showed_up_%, encores_started, encore_started_%, total_watch_time, live_minutes, encore_minutes, reachable_push, reachable_email, reachable_sms, sms_consent, email_sent, email_opened, email_open_rate, push_sent, push_delivered, push_open_rate, last_attended, lives_ago, last_sign_in, joined, source, blocked, tags, notes"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/streams": {
      "get": {
        "operationId": "listStreams",
        "tags": [
          "Streams"
        ],
        "summary": "Your ended lives and their receipts",
        "description": "Your 50 most recently ended lives, newest first. A live that was taken down is left out. No fan appears in this payload. No pagination and no filters.",
        "responses": {
          "200": {
            "description": "Ended lives.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StreamList"
                },
                "examples": {
                  "default": {
                    "value": {
                      "streams": [
                        {
                          "title": "Friday soundcheck",
                          "slug": "friday-soundcheck",
                          "started_at": "2026-10-24T01:00:00Z",
                          "ended_at": "2026-10-24T02:10:00Z",
                          "peak_in_room": 99,
                          "hearts": 412,
                          "cut_retention": {
                            "before": 90,
                            "after": 72,
                            "pct": 80
                          },
                          "broadcasts": [
                            {
                              "trigger": "go_live",
                              "sent_at": "2026-10-24T01:00:12Z",
                              "receipt": {
                                "push": {
                                  "sent": 1,
                                  "delivered": 0,
                                  "opened": 0,
                                  "no_transport": 0,
                                  "suppressed_quiet_hours": 0,
                                  "suppressed_never_activated": 0,
                                  "suppressed_no_consent": 0,
                                  "suppressed_muted": 0,
                                  "suppressed_signal_tier": 0,
                                  "suppressed_digest": 0,
                                  "suppressed_plan_cap": 0,
                                  "suppressed_announcement_type": 0,
                                  "suppressed_frequency_cap": 0,
                                  "suppressed_push_primary": 0,
                                  "failed": 0
                                }
                              },
                              "walked_in_10m": {
                                "push": 1
                              }
                            }
                          ]
                        }
                      ],
                      "generated_at": "2026-10-27T18:04:05Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/passes": {
      "get": {
        "operationId": "listPasses",
        "tags": [
          "Passes"
        ],
        "summary": "Every Pass you have, with its public id",
        "description": "Every Pass on your account, oldest first, with the shelf's state word and every price it is sold at.",
        "responses": {
          "200": {
            "description": "Your Passes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PassList"
                },
                "examples": {
                  "default": {
                    "value": {
                      "passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "status": "published",
                          "prices": [
                            {
                              "cadence": "monthly",
                              "price_cents": 900
                            },
                            {
                              "cadence": "yearly",
                              "price_cents": 9000
                            }
                          ]
                        }
                      ],
                      "generated_at": "2026-10-29T12:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/people": {
      "get": {
        "operationId": "getPerson",
        "tags": [
          "People"
        ],
        "summary": "One person on your list, by email",
        "description": "An Invited person or a signed-in one. A withdrawn invite is a 404.",
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "email"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "examples": {
                  "signed_in": {
                    "value": {
                      "status": "signed_in",
                      "id": 4812,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": "+14155550132",
                      "follower": true,
                      "invited": false,
                      "revoked_at": null,
                      "blocked": false,
                      "access": "1p",
                      "source": "API",
                      "passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "grant",
                          "until": "2026-12-31T23:59:00Z",
                          "active": true
                        }
                      ]
                    }
                  },
                  "invited": {
                    "value": {
                      "status": "invited",
                      "id": null,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": null,
                      "follower": false,
                      "invited": true,
                      "revoked_at": null,
                      "blocked": false,
                      "access": "Invited",
                      "source": "API",
                      "passes": [],
                      "invited_at": "2026-10-29T12:00:00Z",
                      "welcome_sent": true,
                      "queued_passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "until": "2026-12-31T23:59:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "addPerson",
        "tags": [
          "People"
        ],
        "summary": "Add one person, as the Add people sheet on Studio's Followers page does",
        "description": "Adds them as Invited: no account and no follow are created, the Passes are queued on their invite, and the only email they can get before signing in is the welcome letter, when welcome is true (once ever per person). When they sign in they become a follower and every queued Pass is granted, carrying its until. Idempotent on email. Already a follower: the Pass is granted now, and a Pass they hold has its end set to expires_at. 422 when attested is not true, email is missing or unreadable, the phone cannot be read, the pass_id is unknown, archived or another creator's, expires_at has no Pass, is not ISO 8601 or is in the past, or the email is your own account.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "attested"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "attested": {
                    "type": "boolean",
                    "const": true,
                    "description": "You confirm this person consented to be added to your audience and to get email from you. Anything but true adds nobody."
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "If the person already has an account, their own name wins."
                  },
                  "phone": {
                    "type": "string",
                    "description": "Digits with country_code, or E.164 on its own. Stored on their contact row, never a sign-in."
                  },
                  "country_code": {
                    "type": "string",
                    "description": "US, GB or +44: reads phone, as the sheet's country picker does."
                  },
                  "pass_id": {
                    "type": "string",
                    "pattern": "^pass_[a-z0-9]{16}$",
                    "description": "Queues this Pass for them."
                  },
                  "pass_ids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^pass_[a-z0-9]{16}$",
                      "description": "The Pass's public id. Studio's Passes page prints it with a Copy button."
                    },
                    "description": "Several Passes at once. May be sent beside pass_id."
                  },
                  "expires_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "In the future. Requires a Pass. The end of every Pass in this request. Leave it out for a grant with no end."
                  },
                  "welcome": {
                    "type": "boolean",
                    "default": false,
                    "description": "true sends the welcome letter, once ever per person."
                  }
                }
              },
              "examples": {
                "pass_with_expiry_welcome_on": {
                  "value": {
                    "email": "ada@example.com",
                    "name": "Ada Lovelace",
                    "pass_id": "pass_3f9a0c1e7b2d4a68",
                    "expires_at": "2026-12-31T23:59:00Z",
                    "welcome": true,
                    "attested": true
                  }
                },
                "welcome_off": {
                  "value": {
                    "email": "ada@example.com",
                    "pass_id": "pass_3f9a0c1e7b2d4a68",
                    "attested": true,
                    "welcome": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "They were not on your list and are now Invited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "examples": {
                  "welcome_on": {
                    "value": {
                      "status": "invited",
                      "id": null,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": null,
                      "follower": false,
                      "invited": true,
                      "revoked_at": null,
                      "blocked": false,
                      "access": "Invited",
                      "source": "API",
                      "passes": [],
                      "invited_at": "2026-10-29T12:00:00Z",
                      "welcome_sent": true,
                      "queued_passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "until": "2026-12-31T23:59:00Z"
                        }
                      ]
                    }
                  },
                  "welcome_off": {
                    "value": {
                      "status": "invited",
                      "id": null,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": null,
                      "follower": false,
                      "invited": true,
                      "revoked_at": null,
                      "blocked": false,
                      "access": "Invited",
                      "source": "API",
                      "passes": [],
                      "invited_at": "2026-10-29T12:00:00Z",
                      "welcome_sent": false,
                      "queued_passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "until": "2026-12-31T23:59:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "They were already on your list (Invited, or a follower).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "examples": {
                  "already_a_follower": {
                    "value": {
                      "status": "signed_in",
                      "id": 4812,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": "+14155550132",
                      "follower": true,
                      "invited": false,
                      "revoked_at": null,
                      "blocked": false,
                      "access": "1p",
                      "source": "API",
                      "passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "grant",
                          "until": "2026-12-31T23:59:00Z",
                          "active": true
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The request cannot be done as sent. The error is one of these sentences.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "e1": {
                    "summary": "attested was not true.",
                    "value": {
                      "error": "Adding people needs your word first \u2014 confirm everyone here opted in to hear from you by email. Nobody was added."
                    }
                  },
                  "e2": {
                    "summary": "email is required",
                    "value": {
                      "error": "email is required"
                    }
                  },
                  "e3": {
                    "summary": "That email address cannot be read",
                    "value": {
                      "error": "That email address cannot be read"
                    }
                  },
                  "e4": {
                    "summary": "That phone number cannot be read \u2014 send it with its country code, like +14155550132",
                    "value": {
                      "error": "That phone number cannot be read \u2014 send it with its country code, like +14155550132"
                    }
                  },
                  "e5": {
                    "summary": "An unknown id, another creator's Pass, or an archived Pass.",
                    "value": {
                      "error": "No pass with that pass_id on your account"
                    }
                  },
                  "e6": {
                    "summary": "expires_at needs a pass_id",
                    "value": {
                      "error": "expires_at needs a pass_id"
                    }
                  },
                  "e7": {
                    "summary": "expires_at must be an ISO 8601 time, like 2026-12-31T23:59:00Z",
                    "value": {
                      "error": "expires_at must be an ISO 8601 time, like 2026-12-31T23:59:00Z"
                    }
                  },
                  "e8": {
                    "summary": "expires_at is in the past",
                    "value": {
                      "error": "expires_at is in the past"
                    }
                  },
                  "e9": {
                    "summary": "That is your own account",
                    "value": {
                      "error": "That is your own account"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/people/revoke": {
      "post": {
        "operationId": "revokePerson",
        "tags": [
          "People"
        ],
        "summary": "Revoke one Pass, or everything",
        "description": "Invited person: with pass_id, that Pass comes off their queue; without, the invite is withdrawn (status withdrawn, and a GET is then a 404). Signed-in person: with pass_id, a grant ends now and a membership is cancelled at period end (at_period_end) or revoked now (immediate); without pass_id, this is the Followers tab's Revoke for this one person, and the follow row stays stamped Revoked. Nothing is refunded. 422 for a bad mode, an unknown pass_id, or while a Studio bulk act is still running and this person holds a paid membership.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "pass_id": {
                    "type": "string",
                    "pattern": "^pass_[a-z0-9]{16}$",
                    "description": "Leave it out to revoke everything."
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "at_period_end",
                      "immediate"
                    ],
                    "default": "at_period_end",
                    "description": "Only applies to a paid membership on that Pass."
                  }
                }
              },
              "examples": {
                "one_pass_at_period_end": {
                  "value": {
                    "email": "ada@example.com",
                    "pass_id": "pass_3f9a0c1e7b2d4a68",
                    "mode": "at_period_end"
                  }
                },
                "one_pass_immediate": {
                  "value": {
                    "email": "ada@example.com",
                    "pass_id": "pass_3f9a0c1e7b2d4a68",
                    "mode": "immediate"
                  }
                },
                "everything": {
                  "value": {
                    "email": "ada@example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The person, plus what was revoked and what was skipped.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevokeResult"
                },
                "examples": {
                  "one_pass_at_period_end": {
                    "value": {
                      "status": "signed_in",
                      "id": 4812,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": "+14155550132",
                      "follower": true,
                      "invited": false,
                      "revoked_at": null,
                      "blocked": false,
                      "access": "1p",
                      "source": "API",
                      "passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "subscription",
                          "until": "2026-11-30T00:00:00Z",
                          "active": true
                        }
                      ],
                      "revoked": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "subscription",
                          "until": "2026-11-30T00:00:00Z"
                        }
                      ],
                      "skipped": []
                    }
                  },
                  "everything": {
                    "value": {
                      "status": "signed_in",
                      "id": 4812,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": "+14155550132",
                      "follower": false,
                      "invited": false,
                      "revoked_at": "2026-10-29T12:00:00Z",
                      "blocked": false,
                      "access": "Revoked",
                      "source": "API",
                      "passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "subscription",
                          "until": "2026-11-30T00:00:00Z",
                          "active": false
                        },
                        {
                          "pass_id": "pass_9b0e2f6c1a3d5e70",
                          "name": "Back Room",
                          "kind": "grant",
                          "until": "2026-10-29T12:00:00Z",
                          "active": false
                        }
                      ],
                      "revoked": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "subscription",
                          "until": "2026-11-30T00:00:00Z"
                        },
                        {
                          "pass_id": "pass_9b0e2f6c1a3d5e70",
                          "name": "Back Room",
                          "kind": "grant",
                          "until": "2026-10-29T12:00:00Z"
                        },
                        {
                          "name": "Tuesday coaching call",
                          "kind": "ticket"
                        },
                        {
                          "kind": "follow"
                        }
                      ],
                      "skipped": []
                    }
                  },
                  "invite_withdrawn": {
                    "value": {
                      "status": "withdrawn",
                      "id": null,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": null,
                      "follower": false,
                      "invited": false,
                      "revoked_at": null,
                      "blocked": false,
                      "access": null,
                      "source": "API",
                      "passes": [],
                      "revoked": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "queued"
                        },
                        {
                          "kind": "invite"
                        }
                      ],
                      "skipped": []
                    }
                  },
                  "lifetime_seat_skipped": {
                    "value": {
                      "status": "signed_in",
                      "id": 4812,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": "+14155550132",
                      "follower": true,
                      "invited": false,
                      "revoked_at": null,
                      "blocked": false,
                      "access": "1p",
                      "source": "API",
                      "passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "subscription",
                          "until": null,
                          "active": true
                        }
                      ],
                      "revoked": [],
                      "skipped": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "subscription",
                          "reason": "lifetime seat \u2014 nothing renews"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "The request cannot be done as sent. The error is one of these sentences.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "e1": {
                    "summary": "email is required",
                    "value": {
                      "error": "email is required"
                    }
                  },
                  "e2": {
                    "summary": "mode must be at_period_end or immediate",
                    "value": {
                      "error": "mode must be at_period_end or immediate"
                    }
                  },
                  "e3": {
                    "summary": "No pass with that pass_id on your account",
                    "value": {
                      "error": "No pass with that pass_id on your account"
                    }
                  },
                  "e4": {
                    "summary": "A Studio bulk act is still running and this person holds a paid membership.",
                    "value": {
                      "error": "One bulk act at a time \u2014 the last one hasn't finished."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/people/block": {
      "post": {
        "operationId": "blockPerson",
        "tags": [
          "People"
        ],
        "summary": "Block one person",
        "description": "The Followers tab's Block. They cannot enter a live (open ones included), watch an encore or buy. Nothing they paid for is cancelled or refunded. Idempotent. 422 for somebody you invited who has no account yet: withdraw the invite instead.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              },
              "examples": {
                "by_email": {
                  "value": {
                    "email": "ada@example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The person, blocked true.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "examples": {
                  "default": {
                    "value": {
                      "status": "signed_in",
                      "id": 4812,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": "+14155550132",
                      "follower": true,
                      "invited": false,
                      "revoked_at": null,
                      "blocked": true,
                      "access": "Blocked",
                      "source": "API",
                      "passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "grant",
                          "until": "2026-12-31T23:59:00Z",
                          "active": true
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "Somebody you invited who has no account yet: withdraw the invite instead.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "e1": {
                    "summary": "Somebody you invited who has no account yet.",
                    "value": {
                      "error": "not signed in yet \u2014 withdraw the invite instead"
                    }
                  },
                  "e2": {
                    "summary": "email is required",
                    "value": {
                      "error": "email is required"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/people/unblock": {
      "post": {
        "operationId": "unblockPerson",
        "tags": [
          "People"
        ],
        "summary": "Unblock one person",
        "description": "Undoes a block. Every door comes back as it was. Idempotent. 422 for somebody you invited who has no account yet: withdraw the invite instead.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              },
              "examples": {
                "by_email": {
                  "value": {
                    "email": "ada@example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The person, blocked false.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "examples": {
                  "default": {
                    "value": {
                      "status": "signed_in",
                      "id": 4812,
                      "name": "Ada Lovelace",
                      "email": "ada@example.com",
                      "phone": "+14155550132",
                      "follower": true,
                      "invited": false,
                      "revoked_at": null,
                      "blocked": false,
                      "access": "1p",
                      "source": "API",
                      "passes": [
                        {
                          "pass_id": "pass_3f9a0c1e7b2d4a68",
                          "name": "Front Row",
                          "kind": "grant",
                          "until": "2026-12-31T23:59:00Z",
                          "active": true
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "Somebody you invited who has no account yet: withdraw the invite instead.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "e1": {
                    "summary": "Somebody you invited who has no account yet.",
                    "value": {
                      "error": "not signed in yet \u2014 withdraw the invite instead"
                    }
                  },
                  "e2": {
                    "summary": "email is required",
                    "value": {
                      "error": "email is required"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization: Bearer <api-key>. The key is generated by the account owner at Studio > Automations > APIs & Webhooks. 40 alphanumeric characters."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "No key, an unknown key, or a disabled key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "default": {
                "value": {
                  "error": "unauthorized"
                }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "More than 120 requests in one minute with the same Authorization header.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "default": {
                "value": {
                  "error": "rate limited"
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "The email is not on your list (a withdrawn invite included). An account with nothing to do with you is a 404 too.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "default": {
                "value": {
                  "error": "not found"
                }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Plain words. unauthorized (401), rate limited (429), not found (404), or the 422 sentence for the request."
          }
        }
      },
      "Me": {
        "type": "object",
        "required": [
          "handle",
          "display_name",
          "plan"
        ],
        "properties": {
          "handle": {
            "type": "string",
            "description": "Your handle: backstagepass.com/<handle>."
          },
          "display_name": {
            "type": "string"
          },
          "plan": {
            "type": "string",
            "description": "Internal plan identifier."
          }
        }
      },
      "Audience": {
        "type": "object",
        "required": [
          "fans",
          "push_reachable",
          "email_reachable",
          "imported_awaiting_first_sign_in",
          "text_reachable",
          "imported",
          "imported_claimed",
          "generated_at"
        ],
        "properties": {
          "fans": {
            "type": "integer",
            "description": "People who follow you."
          },
          "push_reachable": {
            "type": "integer",
            "description": "Followers a push notification can reach now."
          },
          "email_reachable": {
            "type": "integer",
            "description": "Followers an email can reach now. Does not include imported contacts who have not signed in."
          },
          "imported_awaiting_first_sign_in": {
            "type": "integer",
            "description": "Imported contacts eligible for email who have not signed in yet."
          },
          "text_reachable": {
            "type": "integer",
            "description": "Followers a text message can reach."
          },
          "imported": {
            "type": "integer",
            "description": "Contacts you imported."
          },
          "imported_claimed": {
            "type": "integer",
            "description": "Imported contacts who have since signed in."
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "StreamList": {
        "type": "object",
        "required": [
          "streams",
          "generated_at"
        ],
        "properties": {
          "streams": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/Stream"
            }
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Stream": {
        "type": "object",
        "required": [
          "title",
          "slug",
          "started_at",
          "ended_at",
          "peak_in_room",
          "hearts",
          "cut_retention",
          "broadcasts"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "The live's page: backstagepass.com/<handle>/s/<slug>."
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "peak_in_room": {
            "type": "integer",
            "description": "Most people in the room at once."
          },
          "hearts": {
            "type": "integer",
            "description": "Reactions sent between started_at and ended_at."
          },
          "cut_retention": {
            "description": "Who stayed after CUT THE SOCIALS: the room count at the cut and 10 to 14 minutes later. null when the live was never cut or the samples are missing.",
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "required": [
                  "before",
                  "after",
                  "pct"
                ],
                "properties": {
                  "before": {
                    "type": "integer"
                  },
                  "after": {
                    "type": "integer"
                  },
                  "pct": {
                    "type": "integer",
                    "description": "after / before, as a rounded percentage."
                  }
                }
              }
            ]
          },
          "broadcasts": {
            "type": "array",
            "description": "Every notification blast sent for this live, oldest first.",
            "items": {
              "$ref": "#/components/schemas/Broadcast"
            }
          }
        }
      },
      "Broadcast": {
        "type": "object",
        "required": [
          "trigger",
          "sent_at",
          "receipt",
          "walked_in_10m"
        ],
        "properties": {
          "trigger": {
            "type": "string",
            "description": "What sent it.",
            "enum": [
              "go_live",
              "stream_reminder",
              "went_backstage",
              "clips_ready",
              "canceled",
              "welcome",
              "joined_backstage",
              "win_back",
              "waitlist_seat",
              "ticket_bought",
              "replay_watched",
              "push_granted",
              "gone_quiet",
              "stream_ended",
              "booking_reminder",
              "digest",
              "door_open",
              "show_booked",
              "new_pass",
              "rescheduled",
              "access_granted",
              "counted_in"
            ]
          },
          "sent_at": {
            "type": "string",
            "format": "date-time"
          },
          "receipt": {
            "type": "object",
            "description": "Delivery counts per channel. A channel appears only when at least one of its counts is above zero.",
            "propertyNames": {
              "enum": [
                "push",
                "email",
                "sms",
                "whatsapp"
              ]
            },
            "additionalProperties": {
              "$ref": "#/components/schemas/ChannelReceipt"
            }
          },
          "walked_in_10m": {
            "type": "object",
            "description": "Per channel: distinct people who entered the room within 10 minutes of this notification reaching them. A channel with nobody is left out.",
            "propertyNames": {
              "enum": [
                "push",
                "email",
                "sms",
                "whatsapp"
              ]
            },
            "additionalProperties": {
              "type": "integer"
            }
          }
        }
      },
      "ChannelReceipt": {
        "type": "object",
        "required": [
          "sent",
          "delivered",
          "opened",
          "no_transport",
          "suppressed_quiet_hours",
          "suppressed_never_activated",
          "suppressed_no_consent",
          "suppressed_muted",
          "suppressed_signal_tier",
          "suppressed_digest",
          "suppressed_plan_cap",
          "suppressed_announcement_type",
          "suppressed_frequency_cap",
          "suppressed_push_primary",
          "failed"
        ],
        "properties": {
          "sent": {
            "type": "integer",
            "description": "Rows marked sent or delivered."
          },
          "delivered": {
            "type": "integer"
          },
          "opened": {
            "type": "integer"
          },
          "no_transport": {
            "type": "integer"
          },
          "suppressed_quiet_hours": {
            "type": "integer"
          },
          "suppressed_never_activated": {
            "type": "integer"
          },
          "suppressed_no_consent": {
            "type": "integer"
          },
          "suppressed_muted": {
            "type": "integer"
          },
          "suppressed_signal_tier": {
            "type": "integer"
          },
          "suppressed_digest": {
            "type": "integer"
          },
          "suppressed_plan_cap": {
            "type": "integer"
          },
          "suppressed_announcement_type": {
            "type": "integer"
          },
          "suppressed_frequency_cap": {
            "type": "integer"
          },
          "suppressed_push_primary": {
            "type": "integer"
          },
          "failed": {
            "type": "integer"
          }
        }
      },
      "Pass": {
        "type": "object",
        "required": [
          "pass_id",
          "name",
          "status",
          "prices"
        ],
        "properties": {
          "pass_id": {
            "type": "string",
            "pattern": "^pass_[a-z0-9]{16}$",
            "description": "The Pass's public id. Studio's Passes page prints it with a Copy button."
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "published",
              "link_only",
              "archived",
              "draft"
            ],
            "description": "The word the Pass shelf uses."
          },
          "prices": {
            "type": "array",
            "description": "Every way the Pass is sold.",
            "items": {
              "type": "object",
              "required": [
                "cadence",
                "price_cents"
              ],
              "properties": {
                "cadence": {
                  "type": "string",
                  "enum": [
                    "monthly",
                    "quarterly",
                    "half_yearly",
                    "yearly",
                    "lifetime"
                  ]
                },
                "price_cents": {
                  "type": [
                    "integer",
                    "null"
                  ]
                }
              }
            }
          }
        }
      },
      "PassList": {
        "type": "object",
        "required": [
          "passes",
          "generated_at"
        ],
        "properties": {
          "passes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Pass"
            }
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Person": {
        "type": "object",
        "required": [
          "status",
          "id",
          "name",
          "email",
          "phone",
          "follower",
          "invited",
          "revoked_at",
          "blocked",
          "access",
          "source",
          "passes"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "invited",
              "signed_in",
              "withdrawn"
            ],
            "description": "invited: added, and not signed in since. signed_in: has signed in and is on your list. withdrawn: only in the answer to the revoke that withdrew the invite."
          },
          "id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The person's account id. null for somebody who has never signed in."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "description": "E.164."
          },
          "follower": {
            "type": "boolean",
            "description": "true when they follow you and the follow has not been revoked."
          },
          "invited": {
            "type": "boolean",
            "description": "true when status is invited."
          },
          "revoked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When you revoked them (the follow row stays on your list)."
          },
          "blocked": {
            "type": "boolean",
            "description": "true when you have blocked them. A block closes every door."
          },
          "access": {
            "type": [
              "string",
              "null"
            ],
            "description": "The Followers page's Access chip, word for word: Blocked, Revoked, a count such as 1p \u00b7 2t, Follower, or Invited. null for a withdrawn invite."
          },
          "source": {
            "type": [
              "string",
              "null"
            ],
            "description": "The Followers page's Source column: API, Manual, Organic, or a tracking link's label."
          },
          "passes": {
            "type": "array",
            "description": "One entry per Pass of yours they hold or used to hold. Entries that have run out are included with active: false.",
            "items": {
              "type": "object",
              "required": [
                "pass_id",
                "name",
                "kind",
                "until",
                "active"
              ],
              "properties": {
                "pass_id": {
                  "type": "string",
                  "pattern": "^pass_[a-z0-9]{16}$",
                  "description": "The Pass's public id. Studio's Passes page prints it with a Copy button."
                },
                "name": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "grant",
                    "subscription"
                  ],
                  "description": "grant (you gave it) or subscription (they bought it)."
                },
                "until": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time",
                  "description": "When it ends: the grant's expiry, or the membership's cancel date. null means no end is scheduled."
                },
                "active": {
                  "type": "boolean"
                }
              }
            }
          },
          "invited_at": {
            "type": "string",
            "format": "date-time",
            "description": "Invited only. When you added them."
          },
          "welcome_sent": {
            "type": "boolean",
            "description": "Invited only. Whether the welcome letter has gone."
          },
          "queued_passes": {
            "type": "array",
            "description": "Invited only. The Passes waiting for them, each with the until its grant will carry when they sign in (null for no end).",
            "items": {
              "type": "object",
              "required": [
                "pass_id",
                "until"
              ],
              "properties": {
                "pass_id": {
                  "type": "string",
                  "pattern": "^pass_[a-z0-9]{16}$",
                  "description": "The Pass's public id. Studio's Passes page prints it with a Copy button."
                },
                "until": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "RevokeResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Person"
          },
          {
            "type": "object",
            "required": [
              "revoked",
              "skipped"
            ],
            "properties": {
              "revoked": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "kind"
                  ],
                  "properties": {
                    "kind": {
                      "type": "string",
                      "enum": [
                        "queued",
                        "invite",
                        "grant",
                        "subscription",
                        "ticket",
                        "follow"
                      ]
                    },
                    "pass_id": {
                      "type": "string",
                      "pattern": "^pass_[a-z0-9]{16}$",
                      "description": "The Pass's public id. Studio's Passes page prints it with a Copy button."
                    },
                    "name": {
                      "type": "string"
                    },
                    "until": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              },
              "skipped": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "reason"
                  ],
                  "properties": {
                    "pass_id": {
                      "type": "string",
                      "pattern": "^pass_[a-z0-9]{16}$",
                      "description": "The Pass's public id. Studio's Passes page prints it with a Copy button."
                    },
                    "name": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string"
                    },
                    "reason": {
                      "type": "string",
                      "description": "The bulk tool's own words, such as already winding down, lifetime seat \u2014 nothing renews, not active, holds nothing on this pass."
                    }
                  }
                }
              }
            }
          }
        ]
      }
    }
  }
}
