{
  "openapi": "3.1.0",
  "info": {
    "title": "9in Management API",
    "version": "1",
    "description": "Manage the users and sessions of one tenant environment. Call it on the tenant's own host (production, sandbox or custom domain) with an access token from the client_credentials grant, issued to a confidential application that was given management scopes in the console (Applications → your app → APIs). The environment follows the host."
  },
  "servers": [
    {
      "url": "https://{tenant}.9in.io/api/v1",
      "variables": {
        "tenant": {
          "default": "acme",
          "description": "Your tenant name; use <name>-sandbox for the sandbox."
        }
      }
    }
  ],
  "security": [
    {
      "clientCredentials": []
    }
  ],
  "paths": {
    "/users": {
      "get": {
        "operationId": "listUsers",
        "summary": "List or search users",
        "description": "Newest first. `q` matches email, username, phone or name (substring) or an exact id.",
        "security": [
          {
            "clientCredentials": [
              "management:users:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "nextCursor from the previous page."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of users.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "users",
                    "nextCursor",
                    "total"
                  ],
                  "properties": {
                    "users": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "total": {
                      "type": "integer",
                      "description": "Users in this environment."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createUser",
        "summary": "Create a user",
        "description": "At least one of email, phone or username is required.",
        "security": [
          {
            "clientCredentials": [
              "management:users:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new user.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "user"
                  ],
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_user (details lists the fields), invalid_email, invalid_phone, identifier_required or unsupported_password_hash.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "identifier_taken: another user has this email, phone or username.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/users/lookup": {
      "get": {
        "operationId": "lookupUser",
        "summary": "Find a user by email, phone or username",
        "security": [
          {
            "clientCredentials": [
              "management:users:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "phone",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "username",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The user.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "user"
                  ],
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "None of email, phone or username given.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/users/import": {
      "post": {
        "operationId": "importUsers",
        "summary": "Import users in bulk",
        "description": "Up to 500 users per request (50 when they carry plain-text passwords). Each record is validated on its own; the response has one result per record, in order.",
        "security": [
          {
            "clientCredentials": [
              "management:users:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "users"
                ],
                "properties": {
                  "users": {
                    "type": "array",
                    "maxItems": 500,
                    "items": {
                      "$ref": "#/components/schemas/ImportUser"
                    }
                  },
                  "on_conflict": {
                    "type": "string",
                    "enum": [
                      "skip",
                      "update"
                    ],
                    "default": "skip",
                    "description": "A user with the same id, email, phone, username or social identity already exists: leave it, or update it."
                  },
                  "source": {
                    "type": "string",
                    "pattern": "^[a-z0-9_-]{1,32}$",
                    "description": "Recorded on the user.imported events, e.g. auth0."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One result per record.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "results"
                  ],
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ImportResult"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_request: not { users: [...] }, more than 500 users, or a bad on_conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/users/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "User id."
        }
      ],
      "get": {
        "operationId": "getUser",
        "summary": "Get a user with identities, sessions and two-factor state",
        "security": [
          {
            "clientCredentials": [
              "management:users:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The user and what belongs to them.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "user",
                    "identities",
                    "sessions",
                    "hasPassword",
                    "mfa"
                  ],
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/User"
                    },
                    "identities": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Identity"
                      }
                    },
                    "sessions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Session"
                      }
                    },
                    "hasPassword": {
                      "type": "boolean"
                    },
                    "mfa": {
                      "type": "object",
                      "required": [
                        "enabled"
                      ],
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "since": {
                          "type": "integer"
                        },
                        "recoveryCodesLeft": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateUser",
        "summary": "Update a user",
        "description": "Only the fields you send change. `metadata` replaces the stored metadata. Setting `blocked: true` ends the user's sessions and stops their tokens.",
        "security": [
          {
            "clientCredentials": [
              "management:users:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated user.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "user"
                  ],
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_user, invalid_email, invalid_phone or unsupported_password_hash.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "identifier_taken",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteUser",
        "summary": "Delete a user",
        "description": "Deletes the user, their identities, sessions and tokens. Cannot be undone.",
        "security": [
          {
            "clientCredentials": [
              "management:users:write"
            ]
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/users/{id}/login-link": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "User id."
        }
      ],
      "post": {
        "operationId": "createLoginLink",
        "summary": "Create a single-use sign-in link",
        "description": "The link signs the user in once, within its lifetime. Two-factor authentication still applies.",
        "security": [
          {
            "clientCredentials": [
              "management:users:write"
            ]
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "return_to": {
                    "type": "string",
                    "description": "A registered redirect URL of one of your applications, or a path on the login domain. Default: the account page."
                  },
                  "ttl_seconds": {
                    "type": "integer",
                    "minimum": 60,
                    "maximum": 3600,
                    "default": 600
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The link.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "url",
                    "expires_at"
                  ],
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "expires_at": {
                      "type": "integer",
                      "description": "Unix seconds."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "return_to is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "user_not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The user cannot sign in (for example blocked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/users/{id}/sessions": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "User id."
        }
      ],
      "get": {
        "operationId": "listUserSessions",
        "summary": "List a user's active sessions",
        "security": [
          {
            "clientCredentials": [
              "management:users:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Active sessions, most recently used first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sessions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Session"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "revokeUserSessions",
        "summary": "Sign a user out everywhere",
        "description": "Ends every session of the user and revokes their refresh tokens; access tokens of those sessions stop passing introspection and hybrid verification.",
        "security": [
          {
            "clientCredentials": [
              "management:sessions:write"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "How many sessions ended.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "revoked": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sessions/{sid}": {
      "parameters": [
        {
          "name": "sid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Session id (the `sid` claim)."
        }
      ],
      "delete": {
        "operationId": "revokeSession",
        "summary": "End one session",
        "security": [
          {
            "clientCredentials": [
              "management:sessions:write"
            ]
          }
        ],
        "responses": {
          "204": {
            "description": "Ended."
          },
          "401": {
            "description": "Missing, invalid or expired token (invalid_token).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "clientCredentials": {
        "type": "oauth2",
        "description": "A confidential application with management scopes. Authenticate to the token endpoint with HTTP Basic (client_id:client_secret).",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://{tenant}.9in.io/oauth/token",
            "scopes": {
              "management:users:read": "List, search and read users and their sessions",
              "management:users:write": "Create, update, import, block and delete users; create login links",
              "management:sessions:write": "End sessions"
            }
          }
        }
      }
    },
    "schemas": {
      "User": {
        "type": "object",
        "required": [
          "id",
          "email",
          "email_verified",
          "phone_number",
          "phone_number_verified",
          "username",
          "preferred_username",
          "name",
          "given_name",
          "middle_name",
          "family_name",
          "nickname",
          "gender",
          "website",
          "picture",
          "locale",
          "zoneinfo",
          "birthdate",
          "blocked",
          "metadata",
          "createdAt",
          "updatedAt",
          "lastLoginAt",
          "loginCount"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "usr_… for users created in 9in; imported users can keep their old id. Also the `sub` claim."
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_verified": {
            "type": "boolean"
          },
          "phone_number": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone_number_verified": {
            "type": "boolean"
          },
          "username": {
            "type": [
              "string",
              "null"
            ]
          },
          "preferred_username": {
            "type": [
              "string",
              "null"
            ],
            "description": "Same as username."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "given_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "middle_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "family_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "nickname": {
            "type": [
              "string",
              "null"
            ]
          },
          "gender": {
            "type": [
              "string",
              "null"
            ]
          },
          "website": {
            "type": [
              "string",
              "null"
            ]
          },
          "picture": {
            "type": [
              "string",
              "null"
            ]
          },
          "locale": {
            "type": [
              "string",
              "null"
            ]
          },
          "zoneinfo": {
            "type": [
              "string",
              "null"
            ]
          },
          "birthdate": {
            "type": [
              "string",
              "null"
            ]
          },
          "blocked": {
            "type": "boolean"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          },
          "createdAt": {
            "type": "integer",
            "description": "Milliseconds since the epoch."
          },
          "updatedAt": {
            "type": "integer",
            "description": "Milliseconds since the epoch."
          },
          "lastLoginAt": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Milliseconds since the epoch."
          },
          "loginCount": {
            "type": "integer"
          }
        },
        "description": "A user as the API returns it (OpenID Connect claim names)."
      },
      "UserInput": {
        "type": "object",
        "properties": {
          "email": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 320,
            "description": "Lower-cased and checked."
          },
          "emailVerified": {
            "type": "boolean"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 32,
            "description": "E.164, e.g. +447700900123."
          },
          "phoneVerified": {
            "type": "boolean"
          },
          "username": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 256
          },
          "given_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          },
          "family_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          },
          "picture": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "https URL."
          },
          "locale": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 16
          },
          "zoneinfo": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 64
          },
          "birthdate": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Your own data about the user; replaced as a whole on update."
          },
          "blocked": {
            "type": "boolean",
            "description": "A blocked user cannot sign in, and their sessions and tokens stop working."
          },
          "password": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1024,
            "description": "Plain text; hashed with argon2id. Must meet the tenant's password rules only at sign-up, not here."
          },
          "passwordHash": {
            "type": "string",
            "maxLength": 1024,
            "description": "An existing hash: bcrypt ($2a/$2b/$2y), argon2id/i/d, PBKDF2 (sha1/256/512) or Firebase scrypt. See Importing users."
          }
        },
        "additionalProperties": false,
        "description": "Fields to create or update a user with. Note the names differ from the output in three places: emailVerified, phone and phoneVerified."
      },
      "ImportUser": {
        "type": "object",
        "properties": {
          "email": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 320,
            "description": "Lower-cased and checked."
          },
          "emailVerified": {
            "type": "boolean"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 32,
            "description": "E.164, e.g. +447700900123."
          },
          "phoneVerified": {
            "type": "boolean"
          },
          "username": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 256
          },
          "given_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          },
          "family_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          },
          "picture": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "https URL."
          },
          "locale": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 16
          },
          "zoneinfo": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 64
          },
          "birthdate": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Your own data about the user; replaced as a whole on update."
          },
          "blocked": {
            "type": "boolean",
            "description": "A blocked user cannot sign in, and their sessions and tokens stop working."
          },
          "password": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1024,
            "description": "Plain text; hashed with argon2id. Must meet the tenant's password rules only at sign-up, not here."
          },
          "passwordHash": {
            "type": "string",
            "maxLength": 1024,
            "description": "An existing hash: bcrypt ($2a/$2b/$2y), argon2id/i/d, PBKDF2 (sha1/256/512) or Firebase scrypt. See Importing users."
          },
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9|_.:@+-]{1,128}$",
            "description": "Keep the user's id from the old system (it becomes `sub`)."
          },
          "identities": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "object",
              "required": [
                "connection",
                "subject"
              ],
              "properties": {
                "connection": {
                  "type": "string",
                  "description": "social:<provider>, enterprise:<id> or migration:<source>"
                },
                "subject": {
                  "type": "string"
                }
              }
            }
          },
          "createdAt": {
            "type": "integer",
            "description": "Original sign-up time, ms."
          },
          "lastLoginAt": {
            "type": "integer",
            "description": "ms."
          }
        },
        "additionalProperties": false
      },
      "ImportResult": {
        "type": "object",
        "required": [
          "index",
          "ok",
          "status"
        ],
        "properties": {
          "index": {
            "type": "integer"
          },
          "ok": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "created",
              "updated",
              "skipped",
              "failed"
            ]
          },
          "id": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "description": "Why a record was skipped."
          },
          "error": {
            "type": "string",
            "description": "invalid_user, invalid_email, invalid_phone, identifier_required, unsupported_password_hash, too_many_plaintext_passwords, identifier_taken…"
          },
          "details": {}
        }
      },
      "Identity": {
        "type": "object",
        "properties": {
          "connection": {
            "type": "string",
            "description": "social:google, enterprise:<id>, migration:<source>, adapter, sandbox…"
          },
          "subject": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "profile": {
            "type": "object"
          },
          "createdAt": {
            "type": "integer"
          }
        }
      },
      "Session": {
        "type": "object",
        "properties": {
          "sid": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "authTime": {
            "type": "integer",
            "description": "Unix seconds."
          },
          "amr": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "How the user signed in: pwd, otp, mfa, social, sso, link…"
          },
          "ip": {
            "type": "string"
          },
          "userAgent": {
            "type": "string"
          },
          "createdAt": {
            "type": "integer"
          },
          "lastSeenAt": {
            "type": "integer"
          },
          "expiresAt": {
            "type": "integer"
          },
          "revokedAt": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "error_description": {
            "type": "string"
          },
          "details": {
            "description": "Field problems, as [{ path, message }], for invalid_user."
          }
        }
      }
    }
  }
}
