{
  "openapi": "3.1.0",
  "info": {
    "title": "My SW Flights API",
    "version": "1.0.0",
    "description": "Trips extracted from forwarded Southwest emails, with rebooking savings, Family pooling and share links. Authenticate with a Cognito session token or a personal access token (`Authorization: Bearer mswf_\u2026`). Money is integer cents; points are integers. Errors are application/problem+json. `/v1` only gains fields; breaking changes go to `/v2`."
  },
  "servers": [
    {
      "url": "https://api.myswflights.com"
    }
  ],
  "tags": [
    {
      "name": "trips"
    },
    {
      "name": "account"
    },
    {
      "name": "family"
    },
    {
      "name": "invites"
    },
    {
      "name": "sharing"
    },
    {
      "name": "tokens"
    },
    {
      "name": "meta"
    }
  ],
  "paths": {
    "/v1/demo": {
      "get": {
        "summary": "The dashboard payload for a made-up family (no login)",
        "tags": [
          "meta"
        ],
        "operationId": "demo",
        "parameters": [
          {
            "name": "today",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TripsPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/v1/emails/{emailId}": {
      "get": {
        "summary": "The HTML of a forwarded email",
        "tags": [
          "trips"
        ],
        "operationId": "get_email",
        "parameters": [
          {
            "name": "emailId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailHtml"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: emails:read."
      }
    },
    "/v1/family": {
      "get": {
        "summary": "Your Family",
        "tags": [
          "family"
        ],
        "operationId": "get_family",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Family"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: account:read."
      },
      "post": {
        "summary": "Create a Family",
        "tags": [
          "family"
        ],
        "operationId": "create_family",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FamilyBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Family"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      }
    },
    "/v1/family/leave": {
      "post": {
        "summary": "Leave your Family",
        "tags": [
          "family"
        ],
        "operationId": "leave_family",
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      }
    },
    "/v1/forwarding-emails": {
      "delete": {
        "summary": "Remove a sender address",
        "tags": [
          "account"
        ],
        "operationId": "remove_forwarding",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForwardingEmailBody"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: account:write."
      },
      "get": {
        "summary": "Sender addresses that map to this account",
        "tags": [
          "account"
        ],
        "operationId": "list_forwarding",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ForwardingEmails"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: account:read."
      },
      "post": {
        "summary": "Add a sender address (stored hashed)",
        "tags": [
          "account"
        ],
        "operationId": "add_forwarding",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForwardingEmailBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ForwardingEmails"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: account:write."
      }
    },
    "/v1/health": {
      "get": {
        "summary": "Liveness",
        "tags": [
          "meta"
        ],
        "operationId": "health",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/v1/imports": {
      "get": {
        "summary": "What happened to recent forwarded emails",
        "tags": [
          "account"
        ],
        "operationId": "list_imports",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportsPage"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: account:read."
      }
    },
    "/v1/invites": {
      "get": {
        "summary": "Your invite codes and quota",
        "tags": [
          "invites"
        ],
        "operationId": "list_invites",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invites"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      },
      "post": {
        "summary": "Mint an invite (or a Family link code)",
        "tags": [
          "invites"
        ],
        "operationId": "create_invite",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invite"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      }
    },
    "/v1/invites/redeem": {
      "post": {
        "summary": "Activate this account (or join a Family) with a code",
        "tags": [
          "invites"
        ],
        "operationId": "redeem",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RedeemBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Redeemed"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Callable before the account has redeemed an invite. Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      }
    },
    "/v1/invites/{code}": {
      "delete": {
        "summary": "Revoke an unused invite",
        "tags": [
          "invites"
        ],
        "operationId": "revoke_invite",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      }
    },
    "/v1/me": {
      "get": {
        "summary": "The signed-in account",
        "tags": [
          "account"
        ],
        "operationId": "get_me",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Callable before the account has redeemed an invite. Personal access token scope: account:read."
      },
      "patch": {
        "summary": "Set the name Family members see",
        "tags": [
          "account"
        ],
        "operationId": "patch_me",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DisplayNameBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DisplayName"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: account:write."
      }
    },
    "/v1/me/gmail-verification": {
      "delete": {
        "summary": "Dismiss the pending Gmail forwarding verification",
        "tags": [
          "account"
        ],
        "operationId": "delete_gmail_verification",
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: account:write."
      }
    },
    "/v1/share-links": {
      "get": {
        "summary": "Your read-only share links",
        "tags": [
          "sharing"
        ],
        "operationId": "list_links",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShareLinks"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      },
      "post": {
        "summary": "Create a share link",
        "tags": [
          "sharing"
        ],
        "operationId": "create_link",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ShareLinkBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShareLink"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      }
    },
    "/v1/share-links/{token}": {
      "delete": {
        "summary": "Revoke a share link",
        "tags": [
          "sharing"
        ],
        "operationId": "revoke_link",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      }
    },
    "/v1/shared/{token}": {
      "get": {
        "summary": "Everything a share-link holder may see",
        "tags": [
          "sharing"
        ],
        "operationId": "get_shared",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "today",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SharedPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/v1/shared/{token}/emails/{emailId}": {
      "get": {
        "summary": "An email body, via a share link",
        "tags": [
          "sharing"
        ],
        "operationId": "get_shared_email",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "emailId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailHtml"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/v1/tokens": {
      "get": {
        "summary": "Your personal access tokens",
        "tags": [
          "tokens"
        ],
        "operationId": "list_tokens",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tokens"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      },
      "post": {
        "summary": "Mint a personal access token (the secret is shown once)",
        "tags": [
          "tokens"
        ],
        "operationId": "create_token",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenCreated"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      }
    },
    "/v1/tokens/{tokenId}": {
      "delete": {
        "summary": "Revoke a token",
        "tags": [
          "tokens"
        ],
        "operationId": "revoke_token",
        "parameters": [
          {
            "name": "tokenId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Requires a signed-in session; a personal access token is refused (403 cognito_session_required)."
      }
    },
    "/v1/trips": {
      "get": {
        "summary": "All trips (yours and your Family's), derived and grouped",
        "tags": [
          "trips"
        ],
        "operationId": "list_trips",
        "parameters": [
          {
            "name": "today",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ]
            },
            "description": "The caller's calendar date; decides upcoming vs past. Defaults to the UTC date."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ]
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TripsPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: trips:read."
      }
    },
    "/v1/trips/{date}/{flightNumber}": {
      "get": {
        "summary": "One trip by date and primary flight number",
        "tags": [
          "trips"
        ],
        "operationId": "get_trip",
        "parameters": [
          {
            "name": "date",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "flightNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "today",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Trip"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Personal access token scope: trips:read."
      }
    }
  },
  "components": {
    "schemas": {
      "Airport": {
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "city": {
            "default": "",
            "title": "City",
            "type": "string"
          }
        },
        "required": [
          "code"
        ],
        "title": "Airport",
        "type": "object"
      },
      "Change": {
        "properties": {
          "points": {
            "description": "Positive = saved, negative = paid more.",
            "title": "Points",
            "type": "integer"
          },
          "cashCents": {
            "title": "Cashcents",
            "type": "integer"
          },
          "rows": {
            "items": {
              "$ref": "#/components/schemas/ChangeRow"
            },
            "title": "Rows",
            "type": "array"
          }
        },
        "required": [
          "points",
          "cashCents",
          "rows"
        ],
        "title": "Change",
        "type": "object"
      },
      "ChangeRow": {
        "properties": {
          "passenger": {
            "title": "Passenger",
            "type": "string"
          },
          "before": {
            "$ref": "#/components/schemas/Money"
          },
          "after": {
            "$ref": "#/components/schemas/Money"
          }
        },
        "required": [
          "passenger",
          "before",
          "after"
        ],
        "title": "ChangeRow",
        "type": "object"
      },
      "Confirmation": {
        "properties": {
          "confirmationNumber": {
            "title": "Confirmationnumber",
            "type": "string"
          },
          "status": {
            "enum": [
              "active",
              "cancelled"
            ],
            "title": "Status",
            "type": "string"
          },
          "companion": {
            "default": false,
            "description": "A Companion Pass reservation: no points, only the security fee.",
            "title": "Companion",
            "type": "boolean"
          },
          "bookedByMe": {
            "default": true,
            "title": "Bookedbyme",
            "type": "boolean"
          },
          "bookedBy": {
            "default": "",
            "description": "Display name of the Family member whose inbox received it, when not the viewer.",
            "title": "Bookedby",
            "type": "string"
          },
          "fare": {
            "$ref": "#/components/schemas/Money"
          },
          "tickets": {
            "items": {
              "$ref": "#/components/schemas/Ticket"
            },
            "title": "Tickets",
            "type": "array"
          },
          "emails": {
            "items": {
              "$ref": "#/components/schemas/EmailRef"
            },
            "title": "Emails",
            "type": "array"
          },
          "createdAt": {
            "default": "",
            "title": "Createdat",
            "type": "string"
          },
          "updatedAt": {
            "default": "",
            "title": "Updatedat",
            "type": "string"
          }
        },
        "required": [
          "confirmationNumber",
          "status",
          "fare",
          "tickets",
          "emails"
        ],
        "title": "Confirmation",
        "type": "object"
      },
      "DisplayName": {
        "properties": {
          "displayName": {
            "title": "Displayname",
            "type": "string"
          }
        },
        "required": [
          "displayName"
        ],
        "title": "DisplayName",
        "type": "object"
      },
      "DisplayNameBody": {
        "additionalProperties": false,
        "properties": {
          "displayName": {
            "maxLength": 40,
            "title": "Displayname",
            "type": "string"
          }
        },
        "required": [
          "displayName"
        ],
        "title": "DisplayNameBody",
        "type": "object"
      },
      "EmailHtml": {
        "properties": {
          "html": {
            "title": "Html",
            "type": "string"
          }
        },
        "required": [
          "html"
        ],
        "title": "EmailHtml",
        "type": "object"
      },
      "EmailRef": {
        "properties": {
          "emailId": {
            "default": "",
            "description": "Opaque id for GET /v1/emails/{emailId}; empty when the email body was not kept.",
            "title": "Emailid",
            "type": "string"
          },
          "action": {
            "default": "",
            "title": "Action",
            "type": "string"
          },
          "emailDate": {
            "default": "",
            "title": "Emaildate",
            "type": "string"
          },
          "processedAt": {
            "default": "",
            "description": "When we processed it; a fallback date for very old records without emailDate.",
            "title": "Processedat",
            "type": "string"
          },
          "subject": {
            "default": "",
            "title": "Subject",
            "type": "string"
          }
        },
        "title": "EmailRef",
        "type": "object"
      },
      "Family": {
        "properties": {
          "family": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FamilyInfo"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "family"
        ],
        "title": "Family",
        "type": "object"
      },
      "FamilyBody": {
        "additionalProperties": false,
        "properties": {
          "name": {
            "default": "",
            "maxLength": 40,
            "title": "Name",
            "type": "string"
          }
        },
        "title": "FamilyBody",
        "type": "object"
      },
      "FamilyInfo": {
        "properties": {
          "familyId": {
            "title": "Familyid",
            "type": "string"
          },
          "name": {
            "default": "",
            "title": "Name",
            "type": "string"
          },
          "members": {
            "items": {
              "$ref": "#/components/schemas/FamilyMember"
            },
            "title": "Members",
            "type": "array"
          },
          "myName": {
            "default": "",
            "title": "Myname",
            "type": "string"
          }
        },
        "required": [
          "familyId",
          "members"
        ],
        "title": "FamilyInfo",
        "type": "object"
      },
      "FamilyMember": {
        "properties": {
          "name": {
            "default": "",
            "title": "Name",
            "type": "string"
          },
          "isMe": {
            "title": "Isme",
            "type": "boolean"
          }
        },
        "required": [
          "isMe"
        ],
        "title": "FamilyMember",
        "type": "object"
      },
      "ForwardingEmailBody": {
        "additionalProperties": false,
        "properties": {
          "email": {
            "description": "A sender address whose forwards should land on this account. Stored only as a SHA-256 hash.",
            "maxLength": 254,
            "title": "Email",
            "type": "string"
          }
        },
        "required": [
          "email"
        ],
        "title": "ForwardingEmailBody",
        "type": "object"
      },
      "ForwardingEmails": {
        "properties": {
          "emails": {
            "items": {
              "type": "string"
            },
            "title": "Emails",
            "type": "array"
          }
        },
        "required": [
          "emails"
        ],
        "title": "ForwardingEmails",
        "type": "object"
      },
      "GmailVerification": {
        "properties": {
          "url": {
            "title": "Url",
            "type": "string"
          },
          "receivedAt": {
            "default": "",
            "title": "Receivedat",
            "type": "string"
          }
        },
        "required": [
          "url"
        ],
        "title": "GmailVerification",
        "type": "object"
      },
      "Health": {
        "properties": {
          "status": {
            "const": "ok",
            "default": "ok",
            "title": "Status",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version"
        ],
        "title": "Health",
        "type": "object"
      },
      "Import": {
        "properties": {
          "importId": {
            "title": "Importid",
            "type": "string"
          },
          "receivedAt": {
            "title": "Receivedat",
            "type": "string"
          },
          "source": {
            "default": "email",
            "title": "Source",
            "type": "string"
          },
          "status": {
            "enum": [
              "done",
              "ignored",
              "duplicate",
              "failed"
            ],
            "title": "Status",
            "type": "string"
          },
          "subject": {
            "default": "",
            "title": "Subject",
            "type": "string"
          },
          "confirmationNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Confirmationnumber"
          },
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Reason"
          }
        },
        "required": [
          "importId",
          "receivedAt",
          "status"
        ],
        "title": "Import",
        "type": "object"
      },
      "ImportsPage": {
        "properties": {
          "imports": {
            "items": {
              "$ref": "#/components/schemas/Import"
            },
            "title": "Imports",
            "type": "array"
          }
        },
        "required": [
          "imports"
        ],
        "title": "ImportsPage",
        "type": "object"
      },
      "Invite": {
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "note": {
            "default": "",
            "title": "Note",
            "type": "string"
          },
          "createdAt": {
            "title": "Createdat",
            "type": "string"
          },
          "expiresAt": {
            "default": "",
            "title": "Expiresat",
            "type": "string"
          },
          "status": {
            "enum": [
              "open",
              "used",
              "expired"
            ],
            "title": "Status",
            "type": "string"
          },
          "usedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Usedat"
          },
          "family": {
            "default": false,
            "title": "Family",
            "type": "boolean"
          },
          "joinOnly": {
            "default": false,
            "title": "Joinonly",
            "type": "boolean"
          },
          "url": {
            "title": "Url",
            "type": "string"
          }
        },
        "required": [
          "code",
          "createdAt",
          "status",
          "url"
        ],
        "title": "Invite",
        "type": "object"
      },
      "InviteBody": {
        "additionalProperties": false,
        "properties": {
          "note": {
            "default": "",
            "maxLength": 60,
            "title": "Note",
            "type": "string"
          },
          "family": {
            "default": false,
            "description": "The invite also joins the inviter's Family (created if needed).",
            "title": "Family",
            "type": "boolean"
          },
          "joinOnly": {
            "default": false,
            "description": "A Family link code: joins an existing account, grants nothing, costs no invite.",
            "title": "Joinonly",
            "type": "boolean"
          }
        },
        "title": "InviteBody",
        "type": "object"
      },
      "Invites": {
        "properties": {
          "invites": {
            "items": {
              "$ref": "#/components/schemas/Invite"
            },
            "title": "Invites",
            "type": "array"
          },
          "quota": {
            "title": "Quota",
            "type": "integer"
          },
          "remaining": {
            "title": "Remaining",
            "type": "integer"
          }
        },
        "required": [
          "invites",
          "quota",
          "remaining"
        ],
        "title": "Invites",
        "type": "object"
      },
      "Me": {
        "properties": {
          "userId": {
            "title": "Userid",
            "type": "string"
          },
          "activated": {
            "title": "Activated",
            "type": "boolean"
          },
          "displayName": {
            "default": "",
            "title": "Displayname",
            "type": "string"
          },
          "familyId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Familyid"
          },
          "inviteQuota": {
            "title": "Invitequota",
            "type": "integer"
          },
          "invitesRemaining": {
            "title": "Invitesremaining",
            "type": "integer"
          },
          "inboundEmail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Unique forwarding address; null until activated.",
            "title": "Inboundemail"
          },
          "pendingGmailVerification": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/GmailVerification"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "A Gmail auto-forward confirmation we intercepted; open its url to approve the forward."
          },
          "recentImports": {
            "description": "The last five forwarded emails that did not become a trip (ignored or failed), newest first; the full log is GET /v1/imports.",
            "items": {
              "$ref": "#/components/schemas/Import"
            },
            "title": "Recentimports",
            "type": "array"
          },
          "plan": {
            "default": "free",
            "title": "Plan",
            "type": "string"
          }
        },
        "required": [
          "userId",
          "activated",
          "inviteQuota",
          "invitesRemaining",
          "recentImports"
        ],
        "title": "Me",
        "type": "object"
      },
      "Money": {
        "properties": {
          "points": {
            "default": 0,
            "title": "Points",
            "type": "integer"
          },
          "cashCents": {
            "default": 0,
            "title": "Cashcents",
            "type": "integer"
          }
        },
        "title": "Money",
        "type": "object"
      },
      "Problem": {
        "type": "object",
        "title": "Problem",
        "description": "RFC 9457 problem details; `code` is the stable machine-readable identifier.",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "code"
        ]
      },
      "RedeemBody": {
        "additionalProperties": false,
        "properties": {
          "code": {
            "maxLength": 20,
            "title": "Code",
            "type": "string"
          }
        },
        "required": [
          "code"
        ],
        "title": "RedeemBody",
        "type": "object"
      },
      "Redeemed": {
        "properties": {
          "activated": {
            "title": "Activated",
            "type": "boolean"
          },
          "alreadyActivated": {
            "default": false,
            "title": "Alreadyactivated",
            "type": "boolean"
          },
          "joinedFamily": {
            "default": false,
            "title": "Joinedfamily",
            "type": "boolean"
          }
        },
        "required": [
          "activated"
        ],
        "title": "Redeemed",
        "type": "object"
      },
      "RoundTrip": {
        "properties": {
          "outbound": {
            "items": {
              "$ref": "#/components/schemas/Segment"
            },
            "title": "Outbound",
            "type": "array"
          },
          "return": {
            "items": {
              "$ref": "#/components/schemas/Segment"
            },
            "title": "Return",
            "type": "array"
          }
        },
        "required": [
          "outbound",
          "return"
        ],
        "title": "RoundTrip",
        "type": "object"
      },
      "RouteEnds": {
        "properties": {
          "from": {
            "$ref": "#/components/schemas/Airport"
          },
          "to": {
            "$ref": "#/components/schemas/Airport"
          }
        },
        "required": [
          "from",
          "to"
        ],
        "title": "RouteEnds",
        "type": "object"
      },
      "Segment": {
        "properties": {
          "flightNumber": {
            "title": "Flightnumber",
            "type": "string"
          },
          "departureAirport": {
            "title": "Departureairport",
            "type": "string"
          },
          "arrivalAirport": {
            "title": "Arrivalairport",
            "type": "string"
          },
          "departureCity": {
            "default": "",
            "title": "Departurecity",
            "type": "string"
          },
          "arrivalCity": {
            "default": "",
            "title": "Arrivalcity",
            "type": "string"
          },
          "departureDatetime": {
            "title": "Departuredatetime",
            "type": "string"
          },
          "arrivalDatetime": {
            "title": "Arrivaldatetime",
            "type": "string"
          }
        },
        "required": [
          "flightNumber",
          "departureAirport",
          "arrivalAirport",
          "departureDatetime",
          "arrivalDatetime"
        ],
        "title": "Segment",
        "type": "object"
      },
      "ShareLink": {
        "properties": {
          "token": {
            "title": "Token",
            "type": "string"
          },
          "label": {
            "default": "",
            "title": "Label",
            "type": "string"
          },
          "createdAt": {
            "title": "Createdat",
            "type": "string"
          },
          "url": {
            "title": "Url",
            "type": "string"
          }
        },
        "required": [
          "token",
          "createdAt",
          "url"
        ],
        "title": "ShareLink",
        "type": "object"
      },
      "ShareLinkBody": {
        "additionalProperties": false,
        "properties": {
          "label": {
            "default": "",
            "maxLength": 60,
            "title": "Label",
            "type": "string"
          }
        },
        "title": "ShareLinkBody",
        "type": "object"
      },
      "ShareLinks": {
        "properties": {
          "shareLinks": {
            "items": {
              "$ref": "#/components/schemas/ShareLink"
            },
            "title": "Sharelinks",
            "type": "array"
          }
        },
        "required": [
          "shareLinks"
        ],
        "title": "ShareLinks",
        "type": "object"
      },
      "SharedPage": {
        "properties": {
          "trips": {
            "items": {
              "$ref": "#/components/schemas/Trip"
            },
            "title": "Trips",
            "type": "array"
          },
          "summary": {
            "$ref": "#/components/schemas/Summary"
          },
          "generatedAt": {
            "title": "Generatedat",
            "type": "string"
          },
          "inboundEmail": {
            "title": "Inboundemail",
            "type": "string"
          },
          "label": {
            "default": "",
            "title": "Label",
            "type": "string"
          },
          "sharedAt": {
            "default": "",
            "title": "Sharedat",
            "type": "string"
          }
        },
        "required": [
          "trips",
          "summary",
          "generatedAt",
          "inboundEmail"
        ],
        "title": "SharedPage",
        "type": "object"
      },
      "Summary": {
        "properties": {
          "upcoming": {
            "$ref": "#/components/schemas/Totals"
          },
          "past": {
            "$ref": "#/components/schemas/Totals"
          }
        },
        "required": [
          "upcoming",
          "past"
        ],
        "title": "Summary",
        "type": "object"
      },
      "Ticket": {
        "properties": {
          "ticketNumber": {
            "default": "",
            "title": "Ticketnumber",
            "type": "string"
          },
          "passenger": {
            "title": "Passenger",
            "type": "string"
          },
          "transactionDate": {
            "default": "",
            "title": "Transactiondate",
            "type": "string"
          },
          "points": {
            "default": 0,
            "title": "Points",
            "type": "integer"
          },
          "cashCents": {
            "default": 0,
            "title": "Cashcents",
            "type": "integer"
          },
          "status": {
            "default": "active",
            "enum": [
              "active",
              "voided"
            ],
            "title": "Status",
            "type": "string"
          },
          "action": {
            "default": "new",
            "title": "Action",
            "type": "string"
          }
        },
        "required": [
          "passenger"
        ],
        "title": "Ticket",
        "type": "object"
      },
      "TodayQuery": {
        "properties": {
          "today": {
            "anyOf": [
              {
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Today"
          }
        },
        "title": "TodayQuery",
        "type": "object"
      },
      "Token": {
        "properties": {
          "tokenId": {
            "title": "Tokenid",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "title": "Scopes",
            "type": "array"
          },
          "lastFour": {
            "title": "Lastfour",
            "type": "string"
          },
          "createdAt": {
            "title": "Createdat",
            "type": "string"
          },
          "expiresAt": {
            "title": "Expiresat",
            "type": "string"
          },
          "lastUsedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Lastusedat"
          }
        },
        "required": [
          "tokenId",
          "name",
          "scopes",
          "lastFour",
          "createdAt",
          "expiresAt"
        ],
        "title": "Token",
        "type": "object"
      },
      "TokenBody": {
        "additionalProperties": false,
        "properties": {
          "name": {
            "maxLength": 40,
            "title": "Name",
            "type": "string"
          },
          "scopes": {
            "default": [
              "trips:read",
              "account:read"
            ],
            "items": {
              "enum": [
                "trips:read",
                "account:read",
                "account:write",
                "emails:read"
              ],
              "type": "string"
            },
            "minItems": 1,
            "title": "Scopes",
            "type": "array"
          },
          "expiresInDays": {
            "default": 365,
            "maximum": 365,
            "minimum": 1,
            "title": "Expiresindays",
            "type": "integer"
          }
        },
        "required": [
          "name"
        ],
        "title": "TokenBody",
        "type": "object"
      },
      "TokenCreated": {
        "properties": {
          "tokenId": {
            "title": "Tokenid",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "title": "Scopes",
            "type": "array"
          },
          "lastFour": {
            "title": "Lastfour",
            "type": "string"
          },
          "createdAt": {
            "title": "Createdat",
            "type": "string"
          },
          "expiresAt": {
            "title": "Expiresat",
            "type": "string"
          },
          "lastUsedAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Lastusedat"
          },
          "token": {
            "description": "The secret. Shown once; store it now.",
            "title": "Token",
            "type": "string"
          }
        },
        "required": [
          "tokenId",
          "name",
          "scopes",
          "lastFour",
          "createdAt",
          "expiresAt",
          "token"
        ],
        "title": "TokenCreated",
        "type": "object"
      },
      "Tokens": {
        "properties": {
          "tokens": {
            "items": {
              "$ref": "#/components/schemas/Token"
            },
            "title": "Tokens",
            "type": "array"
          }
        },
        "required": [
          "tokens"
        ],
        "title": "Tokens",
        "type": "object"
      },
      "Totals": {
        "properties": {
          "trips": {
            "title": "Trips",
            "type": "integer"
          },
          "points": {
            "title": "Points",
            "type": "integer"
          },
          "cashCents": {
            "title": "Cashcents",
            "type": "integer"
          },
          "changed": {
            "description": "Trips with a rebooking.",
            "title": "Changed",
            "type": "integer"
          },
          "saved": {
            "$ref": "#/components/schemas/Money"
          }
        },
        "required": [
          "trips",
          "points",
          "cashCents",
          "changed",
          "saved"
        ],
        "title": "Totals",
        "type": "object"
      },
      "Trip": {
        "properties": {
          "flightDate": {
            "title": "Flightdate",
            "type": "string"
          },
          "flightNumber": {
            "description": "Primary (first segment) flight number; with flightDate it identifies the trip.",
            "title": "Flightnumber",
            "type": "string"
          },
          "status": {
            "enum": [
              "active",
              "changed",
              "cancelled"
            ],
            "title": "Status",
            "type": "string"
          },
          "upcoming": {
            "title": "Upcoming",
            "type": "boolean"
          },
          "route": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RouteEnds"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "First departure and final arrival; null when no segments are known."
          },
          "flightNumbers": {
            "items": {
              "type": "string"
            },
            "title": "Flightnumbers",
            "type": "array"
          },
          "segments": {
            "items": {
              "$ref": "#/components/schemas/Segment"
            },
            "title": "Segments",
            "type": "array"
          },
          "roundTrip": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RoundTrip"
              },
              {
                "type": "null"
              }
            ],
            "default": null
          },
          "fare": {
            "$ref": "#/components/schemas/Money"
          },
          "returned": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Refunds on a cancelled trip."
          },
          "change": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Change"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Rebooking delta; present when status is changed."
          },
          "passengers": {
            "description": "First names.",
            "items": {
              "type": "string"
            },
            "title": "Passengers",
            "type": "array"
          },
          "fareCheckUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Southwest search for the same trip, upcoming active trips only.",
            "title": "Farecheckurl"
          },
          "confirmations": {
            "description": "Active first (newest email first), then cancelled.",
            "items": {
              "$ref": "#/components/schemas/Confirmation"
            },
            "title": "Confirmations",
            "type": "array"
          },
          "earlierBookingsFrom": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Index of the first cancelled confirmation when an active one precedes it.",
            "title": "Earlierbookingsfrom"
          }
        },
        "required": [
          "flightDate",
          "flightNumber",
          "status",
          "upcoming",
          "flightNumbers",
          "segments",
          "fare",
          "passengers",
          "confirmations"
        ],
        "title": "Trip",
        "type": "object"
      },
      "TripsPage": {
        "properties": {
          "trips": {
            "items": {
              "$ref": "#/components/schemas/Trip"
            },
            "title": "Trips",
            "type": "array"
          },
          "summary": {
            "$ref": "#/components/schemas/Summary"
          },
          "generatedAt": {
            "title": "Generatedat",
            "type": "string"
          }
        },
        "required": [
          "trips",
          "summary",
          "generatedAt"
        ],
        "title": "TripsPage",
        "type": "object"
      },
      "TripsQuery": {
        "properties": {
          "today": {
            "anyOf": [
              {
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "The caller's calendar date; decides upcoming vs past. Defaults to the UTC date.",
            "title": "Today"
          },
          "from": {
            "anyOf": [
              {
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "From"
          },
          "to": {
            "anyOf": [
              {
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "To"
          }
        },
        "title": "TripsQuery",
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Cognito ID/access token, or a personal access token (mswf_\u2026)"
      }
    }
  },
  "x-error-codes": {
    "400": [
      "validation_error",
      "invalid_code",
      "own_code"
    ],
    "401": [
      "unauthorized",
      "invalid_authorization",
      "invalid_token",
      "token_expired"
    ],
    "403": [
      "invite_required",
      "insufficient_scope",
      "cognito_session_required",
      "no_invites_left",
      "link_only"
    ],
    "404": [
      "not_found",
      "invalid_code"
    ],
    "409": [
      "used",
      "family_conflict",
      "already_in_family",
      "address_in_use",
      "too_many"
    ],
    "410": [
      "expired"
    ],
    "429": [
      "rate_limited"
    ],
    "500": [
      "internal_error",
      "auth_misconfigured"
    ],
    "503": [
      "auth_unavailable"
    ]
  }
}
