2025-10-03 02:20:06 +02:00
|
|
|
|
openapi: 3.0.3
|
|
|
|
|
|
info:
|
|
|
|
|
|
title: Meet External API
|
|
|
|
|
|
version: 1.0.0
|
|
|
|
|
|
description: |
|
|
|
|
|
|
External API for room management with application-delegated authentication.
|
|
|
|
|
|
|
|
|
|
|
|
#### Authentication Flow
|
|
|
|
|
|
|
2025-12-22 09:52:02 +01:00
|
|
|
|
1. Exchange application credentials for a JWT token via `/external-api/v1.0/application/token/`.
|
2025-10-03 02:20:06 +02:00
|
|
|
|
2. Use the JWT token in the `Authorization: Bearer <token>` header for all subsequent requests.
|
|
|
|
|
|
3. Tokens are scoped and allow applications to act on behalf of specific users.
|
|
|
|
|
|
|
|
|
|
|
|
#### Scopes
|
|
|
|
|
|
|
|
|
|
|
|
* `rooms:list` – List rooms accessible to the delegated user.
|
|
|
|
|
|
* `rooms:retrieve` – Retrieve details of a specific room.
|
|
|
|
|
|
* `rooms:create` – Create new rooms.
|
|
|
|
|
|
* `rooms:update` – **Coming soon** Update existing rooms, e.g., add attendees to a room.
|
|
|
|
|
|
* `rooms:delete` – **Coming soon** Delete rooms generated by the application.
|
|
|
|
|
|
|
|
|
|
|
|
#### Upcoming Features
|
|
|
|
|
|
|
|
|
|
|
|
* **Add attendees to a room:** You will be able to update a room to include a list of attendees, allowing them to bypass the lobby system automatically.
|
|
|
|
|
|
* **Delete application-generated rooms:** Rooms created via the application can be deleted when no longer needed.
|
|
|
|
|
|
|
|
|
|
|
|
contact:
|
|
|
|
|
|
name: API Support
|
|
|
|
|
|
email: antoine.lebaud@mail.numerique.gouv.fr
|
|
|
|
|
|
|
|
|
|
|
|
servers:
|
|
|
|
|
|
- url: https://visio-sandbox.beta.numerique.gouv.fr/external-api/v1.0
|
|
|
|
|
|
description: Sandbox server
|
|
|
|
|
|
|
|
|
|
|
|
tags:
|
|
|
|
|
|
- name: Authentication
|
|
|
|
|
|
description: Application authentication and token generation
|
|
|
|
|
|
- name: Rooms
|
|
|
|
|
|
description: Room management operations
|
|
|
|
|
|
|
|
|
|
|
|
paths:
|
2025-12-22 09:52:02 +01:00
|
|
|
|
/application/token/:
|
2025-10-03 02:20:06 +02:00
|
|
|
|
post:
|
|
|
|
|
|
tags:
|
|
|
|
|
|
- Authentication
|
|
|
|
|
|
summary: Generate JWT token
|
|
|
|
|
|
description: |
|
|
|
|
|
|
Exchange application credentials for a scoped JWT token that allows the application
|
|
|
|
|
|
to act on behalf of a specific user.
|
|
|
|
|
|
|
|
|
|
|
|
The application must be authorized for the user's email domain.
|
|
|
|
|
|
The returned token expires after a configured duration and must be refreshed by calling this endpoint again.
|
|
|
|
|
|
operationId: generateToken
|
|
|
|
|
|
requestBody:
|
|
|
|
|
|
required: true
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/TokenRequest'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
tokenRequest:
|
|
|
|
|
|
summary: Request token for user delegation
|
|
|
|
|
|
value:
|
|
|
|
|
|
client_id: "550e8400-e29b-41d4-a716-446655440000"
|
|
|
|
|
|
client_secret: "1234567890abcdefghijklmnopqrstuvwxyz"
|
|
|
|
|
|
grant_type: "client_credentials"
|
|
|
|
|
|
scope: "user@example.com"
|
|
|
|
|
|
responses:
|
|
|
|
|
|
'200':
|
|
|
|
|
|
description: Token generated successfully
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/TokenResponse'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
tokenResponse:
|
|
|
|
|
|
summary: Successful token generation
|
|
|
|
|
|
value:
|
|
|
|
|
|
access_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
|
|
|
|
token_type: "Bearer"
|
|
|
|
|
|
expires_in: 3600
|
|
|
|
|
|
scope: "rooms:list rooms:retrieve rooms:create"
|
|
|
|
|
|
'401':
|
|
|
|
|
|
description: Authentication failed
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/OAuthError'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
invalidCredentials:
|
|
|
|
|
|
summary: Invalid credentials
|
|
|
|
|
|
value:
|
|
|
|
|
|
error: "Invalid credentials"
|
|
|
|
|
|
inactiveApplication:
|
|
|
|
|
|
summary: Application is inactive
|
|
|
|
|
|
value:
|
|
|
|
|
|
error: "Application is inactive"
|
|
|
|
|
|
'400':
|
|
|
|
|
|
description: Invalid request
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/OAuthError'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
userNotFound:
|
|
|
|
|
|
summary: User not found
|
|
|
|
|
|
value:
|
|
|
|
|
|
error: "User not found."
|
|
|
|
|
|
'403':
|
|
|
|
|
|
description: Access denied - cannot delegate user
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/OAuthError'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
delegationDenied:
|
|
|
|
|
|
summary: Domain not authorized
|
|
|
|
|
|
value:
|
|
|
|
|
|
error: "This application is not authorized for this email domain."
|
|
|
|
|
|
|
|
|
|
|
|
/rooms:
|
|
|
|
|
|
get:
|
|
|
|
|
|
tags:
|
|
|
|
|
|
- Rooms
|
|
|
|
|
|
summary: List rooms
|
|
|
|
|
|
description: |
|
|
|
|
|
|
Returns a list of rooms accessible to the authenticated user.
|
|
|
|
|
|
Only rooms where the delegated user has access will be returned.
|
|
|
|
|
|
operationId: listRooms
|
|
|
|
|
|
security:
|
|
|
|
|
|
- BearerAuth: [rooms:list]
|
|
|
|
|
|
parameters:
|
|
|
|
|
|
- name: page
|
|
|
|
|
|
in: query
|
|
|
|
|
|
description: Page number for pagination
|
|
|
|
|
|
schema:
|
|
|
|
|
|
type: integer
|
|
|
|
|
|
minimum: 1
|
|
|
|
|
|
default: 1
|
|
|
|
|
|
- name: page_size
|
|
|
|
|
|
in: query
|
|
|
|
|
|
description: Number of items per page
|
|
|
|
|
|
schema:
|
|
|
|
|
|
type: integer
|
|
|
|
|
|
minimum: 1
|
|
|
|
|
|
maximum: 100
|
|
|
|
|
|
default: 20
|
|
|
|
|
|
responses:
|
|
|
|
|
|
'200':
|
|
|
|
|
|
description: List of accessible rooms
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
type: object
|
|
|
|
|
|
properties:
|
|
|
|
|
|
count:
|
|
|
|
|
|
type: integer
|
|
|
|
|
|
description: Total number of rooms
|
|
|
|
|
|
next:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
nullable: true
|
|
|
|
|
|
description: URL to next page
|
|
|
|
|
|
previous:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
nullable: true
|
|
|
|
|
|
description: URL to previous page
|
|
|
|
|
|
results:
|
|
|
|
|
|
type: array
|
|
|
|
|
|
items:
|
|
|
|
|
|
$ref: '#/components/schemas/Room'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
roomList:
|
|
|
|
|
|
summary: Paginated room list
|
|
|
|
|
|
value:
|
|
|
|
|
|
count: 2
|
|
|
|
|
|
next: "https://visio-sandbox.beta.numerique.gouv.fr/external-api/v1.0/rooms?page=2"
|
|
|
|
|
|
previous: null
|
|
|
|
|
|
results:
|
|
|
|
|
|
- id: "7c9e6679-7425-40de-944b-e07fc1f90ae7"
|
|
|
|
|
|
slug: "aae-erez-aaz"
|
|
|
|
|
|
access_level: "trusted"
|
|
|
|
|
|
url: "https://visio-sandbox.beta.numerique.gouv.fr/aae-erez-aaz"
|
|
|
|
|
|
telephony:
|
|
|
|
|
|
enabled: true
|
|
|
|
|
|
pin_code: "123456"
|
|
|
|
|
|
phone_number: "+1-555-0100"
|
|
|
|
|
|
default_country: "US"
|
|
|
|
|
|
'401':
|
|
|
|
|
|
$ref: '#/components/responses/UnauthorizedError'
|
|
|
|
|
|
'403':
|
|
|
|
|
|
$ref: '#/components/responses/ForbiddenError'
|
|
|
|
|
|
|
|
|
|
|
|
post:
|
|
|
|
|
|
tags:
|
|
|
|
|
|
- Rooms
|
|
|
|
|
|
summary: Create a room
|
|
|
|
|
|
description: |
|
|
|
|
|
|
Creates a new room with secure defaults for external API usage.
|
|
|
|
|
|
|
|
|
|
|
|
**Restrictions:**
|
|
|
|
|
|
- Rooms are always created with `trusted` access (no public rooms via API)
|
|
|
|
|
|
- Room access_level can be updated from the webapp interface.
|
|
|
|
|
|
|
|
|
|
|
|
**Defaults:**
|
|
|
|
|
|
- Delegated user is set as owner
|
|
|
|
|
|
- Room slug auto-generated for uniqueness
|
|
|
|
|
|
- Telephony PIN auto-generated when enabled
|
|
|
|
|
|
- Creation tracked with application client_id for auditing
|
|
|
|
|
|
operationId: createRoom
|
|
|
|
|
|
security:
|
|
|
|
|
|
- BearerAuth: [rooms:create]
|
|
|
|
|
|
requestBody:
|
|
|
|
|
|
required: false
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/RoomCreate'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
emptyBody:
|
|
|
|
|
|
summary: No parameters (default)
|
|
|
|
|
|
value: {}
|
|
|
|
|
|
responses:
|
|
|
|
|
|
'201':
|
|
|
|
|
|
description: Room created successfully
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/Room'
|
|
|
|
|
|
'401':
|
|
|
|
|
|
$ref: '#/components/responses/UnauthorizedError'
|
|
|
|
|
|
'403':
|
|
|
|
|
|
$ref: '#/components/responses/ForbiddenError'
|
|
|
|
|
|
|
|
|
|
|
|
/rooms/{id}:
|
|
|
|
|
|
get:
|
|
|
|
|
|
tags:
|
|
|
|
|
|
- Rooms
|
|
|
|
|
|
summary: Retrieve a room
|
|
|
|
|
|
description: Get detailed information about a specific room by its ID
|
|
|
|
|
|
operationId: retrieveRoom
|
|
|
|
|
|
security:
|
|
|
|
|
|
- BearerAuth: [rooms:retrieve]
|
|
|
|
|
|
parameters:
|
|
|
|
|
|
- name: id
|
|
|
|
|
|
in: path
|
|
|
|
|
|
required: true
|
|
|
|
|
|
description: Room UUID
|
|
|
|
|
|
schema:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
format: uuid
|
|
|
|
|
|
responses:
|
|
|
|
|
|
'200':
|
|
|
|
|
|
description: Room details
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/Room'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
room:
|
|
|
|
|
|
summary: Room details
|
|
|
|
|
|
value:
|
|
|
|
|
|
id: "7c9e6679-7425-40de-944b-e07fc1f90ae7"
|
|
|
|
|
|
slug: "aae-erez-aaz"
|
|
|
|
|
|
access_level: "trusted"
|
|
|
|
|
|
url: "https://visio-sandbox.beta.numerique.gouv.fr/aae-erez-aaz"
|
|
|
|
|
|
telephony:
|
|
|
|
|
|
enabled: true
|
|
|
|
|
|
pin_code: "123456"
|
|
|
|
|
|
phone_number: "+1-555-0100"
|
|
|
|
|
|
default_country: "US"
|
|
|
|
|
|
'401':
|
|
|
|
|
|
$ref: '#/components/responses/UnauthorizedError'
|
|
|
|
|
|
'403':
|
|
|
|
|
|
$ref: '#/components/responses/ForbiddenError'
|
|
|
|
|
|
'404':
|
|
|
|
|
|
$ref: '#/components/responses/RoomNotFoundError'
|
|
|
|
|
|
|
|
|
|
|
|
components:
|
|
|
|
|
|
securitySchemes:
|
|
|
|
|
|
BearerAuth:
|
|
|
|
|
|
type: http
|
|
|
|
|
|
scheme: bearer
|
|
|
|
|
|
bearerFormat: JWT
|
|
|
|
|
|
description: |
|
2025-12-22 09:52:02 +01:00
|
|
|
|
JWT token obtained from the `/application/token/` endpoint.
|
2025-10-03 02:20:06 +02:00
|
|
|
|
Include in requests as: `Authorization: Bearer <token>`
|
|
|
|
|
|
|
|
|
|
|
|
schemas:
|
|
|
|
|
|
TokenRequest:
|
|
|
|
|
|
type: object
|
|
|
|
|
|
required:
|
|
|
|
|
|
- client_id
|
|
|
|
|
|
- client_secret
|
|
|
|
|
|
- grant_type
|
|
|
|
|
|
- scope
|
|
|
|
|
|
properties:
|
|
|
|
|
|
client_id:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: Application client identifier
|
|
|
|
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
|
|
|
|
client_secret:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
format: password
|
|
|
|
|
|
writeOnly: true
|
|
|
|
|
|
description: Application secret key
|
|
|
|
|
|
example: "1234567890abcdefghijklmnopqrstuvwxyz"
|
|
|
|
|
|
grant_type:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
enum:
|
|
|
|
|
|
- client_credentials
|
|
|
|
|
|
description: OAuth2 grant type (must be 'client_credentials')
|
|
|
|
|
|
example: "client_credentials"
|
|
|
|
|
|
scope:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
format: email
|
|
|
|
|
|
description: |
|
|
|
|
|
|
Email address of the user to delegate.
|
|
|
|
|
|
The application will act on behalf of this user.
|
|
|
|
|
|
Note: This parameter is named 'scope' to align with OAuth2 conventions,
|
|
|
|
|
|
but accepts an email address to identify the user. This design allows
|
|
|
|
|
|
for future extensibility.
|
|
|
|
|
|
example: "user@example.com"
|
|
|
|
|
|
|
|
|
|
|
|
TokenResponse:
|
|
|
|
|
|
type: object
|
|
|
|
|
|
properties:
|
|
|
|
|
|
access_token:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: JWT access token
|
|
|
|
|
|
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtZWV0LWFwaSIsImF1ZCI6Im1lZXQtY2xpZW50cyIsImlhdCI6MTcwOTQ5MTIwMCwiZXhwIjoxNzA5NDk0ODAwLCJjbGllbnRfaWQiOiI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAiLCJzY29wZSI6InJvb21zOmxpc3Qgcm9vbXM6cmV0cmlldmUgcm9vbXM6Y3JlYXRlIiwidXNlcl9pZCI6IjdiOGQ5YzQwLTNhMmItNGVkZi04NzFjLTJmM2Q0ZTVmNmE3YiIsImRlbGVnYXRlZCI6dHJ1ZX0.signature"
|
|
|
|
|
|
token_type:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: Token type (always 'Bearer')
|
|
|
|
|
|
example: "Bearer"
|
|
|
|
|
|
expires_in:
|
|
|
|
|
|
type: integer
|
|
|
|
|
|
description: Token lifetime in seconds
|
|
|
|
|
|
example: 3600
|
|
|
|
|
|
scope:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: Space-separated list of granted permission scopes
|
|
|
|
|
|
example: "rooms:list rooms:retrieve rooms:create"
|
|
|
|
|
|
|
|
|
|
|
|
RoomCreate:
|
|
|
|
|
|
type: object
|
|
|
|
|
|
description: Empty object - all room properties are auto-generated
|
|
|
|
|
|
properties: {}
|
|
|
|
|
|
|
|
|
|
|
|
Room:
|
|
|
|
|
|
type: object
|
|
|
|
|
|
properties:
|
|
|
|
|
|
id:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
format: uuid
|
|
|
|
|
|
readOnly: true
|
|
|
|
|
|
description: Unique room identifier
|
|
|
|
|
|
example: "7c9e6679-7425-40de-944b-e07fc1f90ae7"
|
|
|
|
|
|
slug:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
readOnly: true
|
|
|
|
|
|
description: URL-friendly room identifier (auto-generated)
|
|
|
|
|
|
example: "aze-eere-zer"
|
|
|
|
|
|
access_level:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
readOnly: true
|
|
|
|
|
|
description: Room access level (always 'trusted' for API-created rooms)
|
|
|
|
|
|
example: "trusted"
|
|
|
|
|
|
url:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
format: uri
|
|
|
|
|
|
readOnly: true
|
|
|
|
|
|
description: Full URL to access the room
|
|
|
|
|
|
example: "https://visio-sandbox.beta.numerique.gouv.fr/aze-eere-zer"
|
|
|
|
|
|
telephony:
|
|
|
|
|
|
type: object
|
|
|
|
|
|
readOnly: true
|
|
|
|
|
|
description: Telephony dial-in information (if enabled)
|
|
|
|
|
|
properties:
|
|
|
|
|
|
enabled:
|
|
|
|
|
|
type: boolean
|
|
|
|
|
|
description: Whether telephony is available
|
|
|
|
|
|
example: true
|
|
|
|
|
|
pin_code:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: PIN code for dial-in access
|
|
|
|
|
|
example: "123456"
|
|
|
|
|
|
phone_number:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: Phone number to dial
|
|
|
|
|
|
example: "+1-555-0100"
|
|
|
|
|
|
default_country:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: Default country code
|
|
|
|
|
|
example: "US"
|
|
|
|
|
|
|
|
|
|
|
|
OAuthError:
|
|
|
|
|
|
type: object
|
|
|
|
|
|
description: OAuth2-compliant error response
|
|
|
|
|
|
properties:
|
|
|
|
|
|
error:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: Human-readable error description
|
|
|
|
|
|
example: "Invalid credentials"
|
|
|
|
|
|
|
|
|
|
|
|
Error:
|
|
|
|
|
|
type: object
|
|
|
|
|
|
properties:
|
|
|
|
|
|
detail:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: Error message
|
|
|
|
|
|
example: "Invalid token."
|
|
|
|
|
|
|
|
|
|
|
|
ValidationError:
|
|
|
|
|
|
type: object
|
|
|
|
|
|
properties:
|
|
|
|
|
|
field_name:
|
|
|
|
|
|
type: array
|
|
|
|
|
|
items:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
description: List of validation errors for this field
|
|
|
|
|
|
example: ["This field is required."]
|
|
|
|
|
|
|
|
|
|
|
|
responses:
|
|
|
|
|
|
UnauthorizedError:
|
|
|
|
|
|
description: Authentication required or token invalid/expired
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
invalidToken:
|
|
|
|
|
|
summary: Invalid or expired token
|
|
|
|
|
|
value:
|
|
|
|
|
|
error: "Invalid token."
|
|
|
|
|
|
tokenExpired:
|
|
|
|
|
|
summary: Token has expired
|
|
|
|
|
|
value:
|
|
|
|
|
|
error: "Token expired."
|
|
|
|
|
|
|
|
|
|
|
|
ForbiddenError:
|
|
|
|
|
|
description: Insufficient permissions for this operation
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
insufficientScope:
|
|
|
|
|
|
summary: Missing required scope
|
|
|
|
|
|
value:
|
|
|
|
|
|
detail: "Insufficient permissions. Required scope: 'rooms:xxxx'"
|
|
|
|
|
|
|
|
|
|
|
|
RoomNotFoundError:
|
|
|
|
|
|
description: Room not found
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
roomNotFound:
|
|
|
|
|
|
summary: Room does not exist
|
|
|
|
|
|
value:
|
|
|
|
|
|
detail: "Not found."
|
|
|
|
|
|
|
|
|
|
|
|
BadRequestError:
|
|
|
|
|
|
description: Invalid request data
|
|
|
|
|
|
content:
|
|
|
|
|
|
application/json:
|
|
|
|
|
|
schema:
|
|
|
|
|
|
$ref: '#/components/schemas/ValidationError'
|
|
|
|
|
|
examples:
|
|
|
|
|
|
validationError:
|
|
|
|
|
|
summary: Field validation failed
|
|
|
|
|
|
value:
|
|
|
|
|
|
scope: ["Invalid email address."]
|