# Orizon BFF

_Built: 12 Jun 2026, 21:08 (Asia/Yerevan)_

> Error shape (all 4xx/5xx): `{"error": {"code": "string", "message": "string", "details": {}}}`

## health

#### Liveness probe

`GET {baseUrl}/health`
Returns 200/UP as long as the process is running.
200 OK:
```json
{
  "status": "<string>"
}
```

#### Readiness probe

`GET {baseUrl}/ready`
Returns 200/READY when Supabase is reachable; 503/DEGRADED otherwise.
200 OK:
```json
{
  "status": "<string>"
}
```
503 Service Unavailable:
```json
{
  "status": "<string>"
}
```

## auth

#### Check if email is new or existing, send OTP, and return a uid for the OTP request

`POST {baseUrl}/api/v1/auth/initiate`
Body:
```json
{
  "email": "<string>",
  "isSignupToBeAdmin": "<boolean>"
}
```
200 OK:
```json
{
  "data": {
    "isNewUser": "<boolean>",
    "uid": "<string>"
  }
}
```
400 Bad Request: error

#### Resend the email OTP for an existing initiation request

`POST {baseUrl}/api/v1/auth/resend-otp`
Body:
```json
{
  "uid": "<string>"
}
```
202 Accepted: (no body)

#### Verify OTP using the uid from /initiate — completes sign-in or sign-up

`POST {baseUrl}/api/v1/auth/verify-otp`
Body:
```json
{
  "otp": "<string>",
  "uid": "<string>"
}
```
200 OK:
```json
{
  "data": {
    "accessToken": "<string>",
    "availableShops": [
      {
        "id": "<string>",
        "isOwner": "<boolean>",
        "name": "<string>",
        "roleKind": "<string>",
        "status": "<string>",
        "logoUrl": "<null,string>"
      }
    ],
    "expiresAt": "<long>",
    "isNewUser": "<boolean>",
    "isProfileComplete": "<boolean>",
    "memberships": [
      {
        "isOwner": "<boolean>",
        "roleKind": "<string>",
        "serviceId": "<string>",
        "serviceKind": "<string>"
      }
    ],
    "pendingTasks": [
      "<string>"
    ],
    "refreshToken": "<string>",
    "tokenType": "<string>",
    "user": {
      "accountKind": "<string>",
      "email": "<string>",
      "emailConfirmed": "<boolean>",
      "id": "<string>",
      "role": "<string>",
      "username": "<null,string>"
    }
  }
}
```
401 Unauthorized: error

#### Refresh access token

`POST {baseUrl}/api/v1/auth/refresh`
Body:
```json
{
  "refreshToken": "<string>"
}
```
200 OK:
```json
{
  "data": {
    "accessToken": "<string>",
    "availableShops": [
      {
        "id": "<string>",
        "isOwner": "<boolean>",
        "name": "<string>",
        "roleKind": "<string>",
        "status": "<string>",
        "logoUrl": "<null,string>"
      }
    ],
    "expiresAt": "<long>",
    "isNewUser": "<boolean>",
    "isProfileComplete": "<boolean>",
    "memberships": [
      {
        "isOwner": "<boolean>",
        "roleKind": "<string>",
        "serviceId": "<string>",
        "serviceKind": "<string>"
      }
    ],
    "pendingTasks": [
      "<string>"
    ],
    "refreshToken": "<string>",
    "tokenType": "<string>",
    "user": {
      "accountKind": "<string>",
      "email": "<string>",
      "emailConfirmed": "<boolean>",
      "id": "<string>",
      "role": "<string>",
      "username": "<null,string>"
    }
  }
}
```
401 Unauthorized: error

#### Current session context: identity, account kind, memberships, pending tasks

`GET {baseUrl}/api/v1/auth/session`
200 OK:
```json
{
  "data": {
    "availableShops": [
      {
        "id": "<string>",
        "isOwner": "<boolean>",
        "name": "<string>",
        "roleKind": "<string>",
        "status": "<string>",
        "logoUrl": "<null,string>"
      }
    ],
    "memberships": [
      {
        "isOwner": "<boolean>",
        "roleKind": "<string>",
        "serviceId": "<string>",
        "serviceKind": "<string>"
      }
    ],
    "pendingTasks": [
      "<string>"
    ],
    "user": {
      "accountKind": "<string>",
      "email": "<string>",
      "emailConfirmed": "<boolean>",
      "id": "<string>",
      "role": "<string>",
      "username": "<null,string>"
    }
  }
}
```
401 Unauthorized: error

#### Account type (user/admin) and the caller's service memberships with lifecycle status

`GET {baseUrl}/api/v1/auth/permissions`
200 OK:
```json
{
  "data": {
    "accountType": "<string>",
    "memberships": [
      {
        "role": "<string>",
        "serviceId": "<string>",
        "serviceKind": "<string>",
        "serviceName": "<string>",
        "status": "<string>",
        "email": "<null,string>"
      }
    ]
  }
}
```
401 Unauthorized: error

#### Sign out

`POST {baseUrl}/api/v1/auth/sign-out`
204 No Content: (no body)

#### Permanently delete the caller's account (consumer or admin). Frees the email to register again as the other account type.

`DELETE {baseUrl}/api/v1/auth/account`
204 No Content: (no body)
401 Unauthorized: error

#### Complete essential profile data after first sign-in

`POST {baseUrl}/api/v1/auth/complete-profile`
Body:
```json
{
  "fullName": "<string>"
}
```
200 OK: (no body)
400 Bad Request: error

## profile

#### Get current user profile

`GET {baseUrl}/api/v1/profile`
Returns the authenticated normal user's profile fields from public.profiles.
200 OK:
```json
{
  "data": {
    "id": "<string>",
    "isDeveloper": "<boolean>",
    "isEmailVerified": "<boolean>",
    "isPhoneVerified": "<boolean>",
    "avatarUrlLarge": "<null,string>",
    "avatarUrlSmall": "<null,string>",
    "dateOfBirth": "<null,string>",
    "email": "<null,string>",
    "firstName": "<null,string>",
    "gender": "<null,string>",
    "lastName": "<null,string>",
    "phoneNumber": "<null,string>",
    "updatedAt": "<null,string>",
    "userSignupDate": "<null,string>",
    "username": "<null,string>"
  }
}
```
401 Unauthorized: error
403 Forbidden: error
404 Not Found: error

## shops

#### Create a new shop

`POST {baseUrl}/api/v1/shops`
Body:
```json
{
  "cartReservationHours": "<integer>",
  "currencyCode": "<string>",
  "email": "<string>",
  "name": "<string>",
  "slug": "<string>",
  "socialLinks": {
    "<key>": "<string>"
  },
  "taxRate": "<double>",
  "addressLine1": "<null,string>",
  "addressLine2": "<null,string>",
  "bannerUrl": "<null,string>",
  "city": "<null,string>",
  "countryCode": "<null,string>",
  "description": "<null,string>",
  "latitude": "<null,number-double>",
  "logoUrl": "<null,string>",
  "longitude": "<null,number-double>",
  "phone": "<null,string>",
  "postalCode": "<null,string>",
  "stateProvince": "<null,string>",
  "websiteUrl": "<null,string>"
}
```
201 Created:
```json
{
  "data": "<string>"
}
```
400 Bad Request: error
409 Conflict: error

#### Get shop by ID

`GET {baseUrl}/api/v1/shops/:shopId`
200 OK:
```json
{
  "data": {
    "cartReservationHours": "<integer>",
    "currencyCode": "<string>",
    "email": "<string>",
    "id": "<string>",
    "isActive": "<boolean>",
    "isVerified": "<boolean>",
    "name": "<string>",
    "slug": "<string>",
    "socialLinks": {
      "<key>": "<string>"
    },
    "status": "<string>",
    "taxRate": "<double>",
    "addressLine1": "<null,string>",
    "addressLine2": "<null,string>",
    "bannerUrl": "<null,string>",
    "city": "<null,string>",
    "countryCode": "<null,string>",
    "description": "<null,string>",
    "latitude": "<null,number-double>",
    "logoUrl": "<null,string>",
    "longitude": "<null,number-double>",
    "phone": "<null,string>",
    "postalCode": "<null,string>",
    "stateProvince": "<null,string>",
    "websiteUrl": "<null,string>"
  }
}
```
404 Not Found: error

#### Soft-delete shop

`DELETE {baseUrl}/api/v1/shops/:shopId`
204 No Content: (no body)
403 Forbidden: error
404 Not Found: error

#### Update shop fields

`PATCH {baseUrl}/api/v1/shops/:shopId`
Body:
```json
{
  "addressLine1": "<null,string>",
  "addressLine2": "<null,string>",
  "bannerUrl": "<null,string>",
  "cartReservationHours": "<null,integer-int32>",
  "city": "<null,string>",
  "countryCode": "<null,string>",
  "currencyCode": "<null,string>",
  "description": "<null,string>",
  "email": "<null,string>",
  "latitude": "<null,number-double>",
  "logoUrl": "<null,string>",
  "longitude": "<null,number-double>",
  "name": "<null,string>",
  "phone": "<null,string>",
  "postalCode": "<null,string>",
  "socialLinks": {
    "<key>": "<string>"
  },
  "stateProvince": "<null,string>",
  "taxRate": "<null,number-double>",
  "websiteUrl": "<null,string>"
}
```
200 OK: (no body)
403 Forbidden: error
404 Not Found: error

#### Approve a pending shop

`POST {baseUrl}/api/v1/shops/:shopId/approve`
200 OK: (no body)
403 Forbidden: error
404 Not Found: error

#### Reject a pending shop

`POST {baseUrl}/api/v1/shops/:shopId/reject`
200 OK: (no body)
403 Forbidden: error
404 Not Found: error

#### List shop members

`GET {baseUrl}/api/v1/shops/:shopId/members`
200 OK:
```json
{
  "data": [
    {
      "isOwner": "<boolean>",
      "joinedAt": "<string>",
      "roleKind": "<string>",
      "status": "<string>",
      "userId": "<string>",
      "profileEmail": "<null,string>",
      "username": "<null,string>"
    }
  ]
}
```
404 Not Found: error

#### Invite a member to the shop

`POST {baseUrl}/api/v1/shops/:shopId/members/invite`
Body:
```json
{
  "email": "<string>",
  "roleKind": "<string>",
  "desiredUsername": "<null,string>"
}
```
201 Created:
```json
{
  "data": {
    "invitationId": "<string>",
    "token": "<string>"
  }
}
```
400 Bad Request: error

#### Remove a member from the shop

`DELETE {baseUrl}/api/v1/shops/:shopId/members/:targetUserId`
204 No Content: (no body)
403 Forbidden: error
404 Not Found: error

#### List pending invitations for the shop

`GET {baseUrl}/api/v1/shops/:shopId/invitations`
200 OK:
```json
{
  "data": [
    {
      "createdAt": "<string>",
      "email": "<string>",
      "expiresAt": "<string>",
      "id": "<string>",
      "invitedBy": "<string>",
      "roleKind": "<string>",
      "status": "<string>",
      "desiredUsername": "<null,string>"
    }
  ]
}
```
404 Not Found: error

#### Revoke a shop invitation

`DELETE {baseUrl}/api/v1/shops/invitations/:invitationId`
204 No Content: (no body)
403 Forbidden: error
404 Not Found: error

#### Consume a shop invitation token

`POST {baseUrl}/api/v1/shops/invitations/consume`
Body:
```json
{
  "token": "<string>"
}
```
200 OK: (no body)
400 Bad Request: error
401 Unauthorized: error

## clinics

#### Register a veterinary clinic (admin accounts only). Starts pending verification.

`POST {baseUrl}/api/v1/clinics`
Body:
```json
{
  "appointmentDurationMinutes": "<integer>",
  "email": "<string>",
  "emergencyAvailable": "<boolean>",
  "name": "<string>",
  "slug": "<string>",
  "addressLine1": "<null,string>",
  "addressLine2": "<null,string>",
  "city": "<null,string>",
  "countryCode": "<null,string>",
  "description": "<null,string>",
  "emergencyPhone": "<null,string>",
  "latitude": "<null,number-double>",
  "logoUrl": "<null,string>",
  "longitude": "<null,number-double>",
  "phone": "<null,string>",
  "postalCode": "<null,string>",
  "stateProvince": "<null,string>",
  "websiteUrl": "<null,string>"
}
```
201 Created:
```json
{
  "data": "<string>"
}
```
400 Bad Request: error
403 Forbidden: error
409 Conflict: error

#### Get a clinic by id

`GET {baseUrl}/api/v1/clinics/:clinicId`
200 OK:
```json
{
  "data": {
    "appointmentDurationMinutes": "<integer>",
    "email": "<string>",
    "emergencyAvailable": "<boolean>",
    "id": "<string>",
    "isActive": "<boolean>",
    "isVerified": "<boolean>",
    "name": "<string>",
    "slug": "<string>",
    "status": "<string>",
    "addressLine1": "<null,string>",
    "addressLine2": "<null,string>",
    "city": "<null,string>",
    "countryCode": "<null,string>",
    "description": "<null,string>",
    "emergencyPhone": "<null,string>",
    "latitude": "<null,number-double>",
    "logoUrl": "<null,string>",
    "longitude": "<null,number-double>",
    "phone": "<null,string>",
    "postalCode": "<null,string>",
    "stateProvince": "<null,string>",
    "websiteUrl": "<null,string>"
  }
}
```
404 Not Found: error

#### Soft-delete a clinic (owner only)

`DELETE {baseUrl}/api/v1/clinics/:clinicId`
204 No Content: (no body)
403 Forbidden: error
404 Not Found: error

#### Update clinic fields (clinic members)

`PATCH {baseUrl}/api/v1/clinics/:clinicId`
Body:
```json
{
  "addressLine1": "<null,string>",
  "addressLine2": "<null,string>",
  "appointmentDurationMinutes": "<null,integer-int32>",
  "city": "<null,string>",
  "countryCode": "<null,string>",
  "description": "<null,string>",
  "email": "<null,string>",
  "emergencyAvailable": "<null,boolean>",
  "emergencyPhone": "<null,string>",
  "latitude": "<null,number-double>",
  "logoUrl": "<null,string>",
  "longitude": "<null,number-double>",
  "name": "<null,string>",
  "phone": "<null,string>",
  "postalCode": "<null,string>",
  "stateProvince": "<null,string>",
  "websiteUrl": "<null,string>"
}
```
200 OK: (no body)
403 Forbidden: error
404 Not Found: error

#### Approve a pending clinic (platform superadmin only)

`POST {baseUrl}/api/v1/clinics/:clinicId/approve`
200 OK: (no body)
403 Forbidden: error
404 Not Found: error

#### Reject/suspend a clinic (platform superadmin only)

`POST {baseUrl}/api/v1/clinics/:clinicId/reject`
200 OK: (no body)
403 Forbidden: error
404 Not Found: error

#### List clinic members

`GET {baseUrl}/api/v1/clinics/:clinicId/members`
200 OK:
```json
{
  "data": [
    {
      "isOwner": "<boolean>",
      "joinedAt": "<string>",
      "roleKind": "<string>",
      "status": "<string>",
      "userId": "<string>",
      "email": "<null,string>",
      "firstName": "<null,string>",
      "lastName": "<null,string>"
    }
  ]
}
```
404 Not Found: error

#### Invite a member to the clinic (owner only)

`POST {baseUrl}/api/v1/clinics/:clinicId/members/invite`
Body:
```json
{
  "email": "<string>",
  "roleKind": "<string>"
}
```
201 Created:
```json
{
  "data": {
    "invitationId": "<string>",
    "token": "<string>"
  }
}
```
400 Bad Request: error
403 Forbidden: error

#### Remove a member from the clinic (owner only)

`DELETE {baseUrl}/api/v1/clinics/:clinicId/members/:targetUserId`
204 No Content: (no body)
403 Forbidden: error
404 Not Found: error

#### List pending clinic invitations (owner only)

`GET {baseUrl}/api/v1/clinics/:clinicId/invitations`
200 OK:
```json
{
  "data": [
    {
      "createdAt": "<string>",
      "email": "<string>",
      "expiresAt": "<string>",
      "id": "<string>",
      "invitedBy": "<string>",
      "roleKind": "<string>",
      "status": "<string>"
    }
  ]
}
```
403 Forbidden: error

#### Revoke a clinic invitation (owner only)

`DELETE {baseUrl}/api/v1/clinics/invitations/:invitationId`
204 No Content: (no body)
403 Forbidden: error
404 Not Found: error

#### Consume a clinic invitation token (admin accounts only)

`POST {baseUrl}/api/v1/clinics/invitations/consume`
Body:
```json
{
  "token": "<string>"
}
```
200 OK: (no body)
400 Bad Request: error
403 Forbidden: error

## admin

#### Admin portal landing context: which portal(s) to open, the admin's name, and memberships

`GET {baseUrl}/api/v1/admin/dashboard`
200 OK:
```json
{
  "data": {
    "accountType": "<string>",
    "memberships": [
      {
        "role": "<string>",
        "serviceId": "<string>",
        "serviceKind": "<string>",
        "serviceName": "<string>",
        "status": "<string>",
        "email": "<null,string>"
      }
    ],
    "portals": [
      "<string>"
    ],
    "user": {
      "email": "<null,string>",
      "firstName": "<null,string>",
      "lastName": "<null,string>"
    }
  }
}
```
403 Forbidden: error
