FairePlace Owner Claim API
Owner-claim flow: public token-based claim view, claim confirmation, and the authenticated start of an owner claim.
Owner-claim flow: public token-based claim view, claim confirmation, and the authenticated start of an owner claim.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/faireplace-com:faireplace-com-owner-claim-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: FairePlace Property Management Owner Claim API
description: 'Comprehensive API for managing properties, leases, tenants, and all aspects of real estate management.
Built with Rust and Actix-web following hexagonal architecture principles.
## Authentication
This API uses API keys for authentication with tenant-based isolation.
## Base URL
- Production: `https://api.faireplace.com/api`'
version: 1.0.0
contact:
name: FairePlace API Support
email: api-support@faireplace.com
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: https://api.faireplace.com/api
description: Production server
security:
- BearerAuth: []
tags:
- name: Owner Claim
description: 'Owner-claim flow: public token-based claim view, claim confirmation, and the
authenticated start of an owner claim.'
paths:
/owner-claim/{token}:
get:
operationId: viewOwnerClaimDetails
summary: View owner claim details
description: 'Returns a minimal public summary of an owner claim so the recipient can
confirm they are looking at the right request before logging in.
## Authentication
This endpoint is **public** (the user is not yet authenticated when they
click the email link). The only credential is the claim token in the URL
path.
## Privacy
Anti-leak by design: the initiator email is masked
(`jo***@example.com`), the owner email is never returned, and no internal
IDs are exposed. Unknown / consumed tokens return a generic `404`
(anti-oracle); responses are padded to a constant minimum latency.
## Example
```bash
curl https://api.faireplace.com/api/owner-claim/3f8b1c2d-...-9a0e
```
**Response**:
```json
{
"initiator_email_partial": "jo***@example.com",
"owner_display_name": "Jean Dupont",
"expires_at": "2026-06-27T10:00:00Z"
}
```'
tags:
- Owner Claim
security: []
parameters:
- name: token
in: path
required: true
description: Owner claim token (clear value from the email link).
schema:
type: string
example: 3f8b1c2d-4e5f-6a7b-8c9d-0e1f2a3b4c5d
responses:
'200':
description: Owner claim details retrieved.
headers:
Cache-Control:
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimDetailsView'
'404':
description: Token invalid, not found, consumed, or malformed (generic, anti-oracle).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_NOT_FOUND
message: Demande introuvable.
'410':
description: The claim has expired (or been consumed).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_GONE
message: Demande expirée
'500':
description: Internal error (no infra details leaked).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_INTERNAL
message: Une erreur est survenue, veuillez réessayer.
/owner-claim/{token}/confirm:
post:
operationId: confirmOwnerClaim
summary: Confirm an owner claim
description: 'Finalizes an owner claim: links `owner.auth_user_id` to the currently
authenticated account and marks the claim session as consumed.
## Authentication
Unlike the `GET` above, this endpoint **requires authentication**
(Bearer JWT, `properties:read` permission). The user must be logged in;
the confirmation matches the authenticated account against the claim
initiator. The token is still read from the URL path.
## Body
The request body may be empty: the confirmation is derived from the JWT
and the path token.
## Example
```bash
curl -X POST https://api.faireplace.com/api/owner-claim/3f8b1c2d-...-9a0e/confirm \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d ''{}''
```
**Response**:
```json
{
"owner_id": "550e8400-e29b-41d4-a716-446655440000",
"claimed_at": "2026-06-20T14:30:00Z"
}
```'
tags:
- Owner Claim
security:
- BearerAuth: []
parameters:
- name: token
in: path
required: true
description: Owner claim token (clear value from the email link).
schema:
type: string
example: 3f8b1c2d-4e5f-6a7b-8c9d-0e1f2a3b4c5d
requestBody:
required: false
description: 'Empty body accepted: confirmation derives from the JWT and path token.'
content:
application/json:
schema:
$ref: '#/components/schemas/ConfirmOwnerClaimBody'
example: {}
responses:
'200':
description: Claim confirmed and linked to the authenticated account.
content:
application/json:
schema:
$ref: '#/components/schemas/ConfirmOwnerClaimResponse'
example:
owner_id: 550e8400-e29b-41d4-a716-446655440000
claimed_at: '2026-06-20T14:30:00Z'
'400':
description: Validation error on the claim.
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_VALIDATION
message: Requête invalide.
'401':
$ref: '#/components/responses/Unauthorized'
'403':
description: The authenticated user is not allowed to confirm this claim (generic message).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_FORBIDDEN
message: Vous n'êtes pas autorisé à effectuer cette action.
'404':
description: Token invalid, not found, or malformed (generic, anti-oracle).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_NOT_FOUND
message: Demande introuvable.
'409':
description: 'Conflict: the owner has already been claimed.'
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_CONFLICT
message: Cet owner a déjà été revendiqué.
'410':
description: The claim has expired or has already been used.
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_GONE
message: Demande expirée
'500':
description: Internal error (no infra details leaked).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_INTERNAL
message: Une erreur est survenue, veuillez réessayer.
'502':
description: Downstream notifier/service unavailable.
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_NOTIFIER_DOWN
message: Service temporairement indisponible.
/owners/{owner_id}/claim/start:
post:
operationId: startOwnerClaim
summary: Start an owner claim
description: 'Starts an owner-claim workflow for the given `owner_id`. The backend
generates a token, persists the claim session, and the targeted owner
receives an email containing the confirmation link.
## Authentication
This endpoint **requires authentication** (Bearer JWT, `properties:write`
permission): it modifies the account ↔ owner association. The initiator
identity (auth user id + email) and tenant are taken from the JWT.
The claim TTL defaults to 7 days (168 hours).
## Example
```bash
curl -X POST https://api.faireplace.com/api/owners/550e8400-e29b-41d4-a716-446655440000/claim/start \
-H "Authorization: Bearer YOUR_API_KEY"
```
**Response** (`201 Created`):
```json
{
"frontend_url": "https://app.faireplace.com/owner-claim/3f8b1c2d-...-9a0e",
"owner_email": "owner@example.com"
}
```'
tags:
- Owner Claim
security:
- BearerAuth: []
parameters:
- name: owner_id
in: path
required: true
description: Identifier of the owner to start a claim for.
schema:
type: string
format: uuid
example: 550e8400-e29b-41d4-a716-446655440000
responses:
'201':
description: Claim started; the link has been issued for the owner.
content:
application/json:
schema:
$ref: '#/components/schemas/StartOwnerClaimResponse'
example:
frontend_url: https://app.faireplace.com/owner-claim/3f8b1c2d-4e5f-6a7b-8c9d-0e1f2a3b4c5d
owner_email: owner@example.com
'400':
description: Validation error (e.g. invalid owner_id or claim parameters).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_VALIDATION
message: Requête invalide.
'401':
$ref: '#/components/responses/Unauthorized'
'403':
description: The authenticated user is not allowed to start a claim for this owner (generic message).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_FORBIDDEN
message: Vous n'êtes pas autorisé à effectuer cette action.
'404':
description: Owner not found.
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_NOT_FOUND
message: Demande introuvable.
'409':
description: 'Conflict: the owner has already been claimed.'
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_CONFLICT
message: Cet owner a déjà été revendiqué.
'500':
description: Internal error (no infra details leaked).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_INTERNAL
message: Une erreur est survenue, veuillez réessayer.
'502':
description: Downstream notifier/service unavailable (email could not be dispatched).
content:
application/json:
schema:
$ref: '#/components/schemas/OwnerClaimError'
example:
error_code: OWNER_CLAIM_NOTIFIER_DOWN
message: Service temporairement indisponible.
components:
schemas:
OwnerClaimDetailsView:
type: object
description: 'Minimal public summary shown on the confirmation screen before login.
Anti-leak: the initiator email is masked, the owner email is never
returned, and no internal IDs (auth_user_id, owner_id) are exposed.
'
required:
- initiator_email_partial
- owner_display_name
- expires_at
properties:
initiator_email_partial:
type: string
description: Masked initiator email (first chars + domain), e.g. `jo***@example.com`.
example: jo***@example.com
owner_display_name:
type: string
description: Owner display name (last name, plus first name for individuals).
example: Jean Dupont
expires_at:
type: string
format: date-time
description: Expiration date of the claim session.
example: '2026-06-27T10:00:00Z'
Error:
type: object
description: "The error envelope returned by every authenticated endpoint.\n\nTwo things are worth knowing before you write your error handling:\n\n- **`code` is a symbolic string, not a number.** The numeric HTTP status is\n in `status`. Branch on `code`: it is stable, and show `message`, which\n is written for humans and may be reworded without notice.\n- The public guest-signature endpoints use a **different, flatter shape**\n (`{ \"error_code\": …, \"message\": … }`, no `error` wrapper), because they\n are consumed by a page that has no session. Their responses document it\n inline.\n\nThe `X-Request-Id` response header carries the request identifier: quote it\nwhen reporting a problem. It is a header, not a body field.\n"
required:
- error
properties:
error:
type: object
required:
- code
- message
- status
properties:
code:
type: string
description: Stable symbolic code. Branch on this.
enum:
- NOT_FOUND
- UNAUTHORIZED
- VALIDATION_ERROR
- DATABASE_ERROR
- BUSINESS_ERROR
- STORAGE_ERROR
- CONFIG_ERROR
- FORBIDDEN
- CONFLICT
- PARSE_ERROR
- SERIALIZATION_ERROR
- AUTHENTICATION_ERROR
- AUTHORIZATION_ERROR
- EXTERNAL_SERVICE_ERROR
- RATE_LIMIT_EXCEEDED
- PAYMENT_REQUIRED
- PLAN_LIMIT_REACHED
- GONE
- BAD_REQUEST
- INTERNAL_ERROR
- INTERNAL_SERVER_ERROR
example: NOT_FOUND
message:
type: string
description: 'Human-readable explanation, most often in French. Safe to display,
not safe to parse.
'
example: Lease not found
status:
type: integer
description: The HTTP status code, repeated in the body.
example: 404
details:
type: object
additionalProperties: true
description: 'Extra machine-readable context. Only present on some errors: on
`RATE_LIMIT_EXCEEDED` it carries `retry_after_seconds`.
'
example:
retry_after_seconds: 12
ConfirmOwnerClaimResponse:
type: object
description: Response after a guest claim has been confirmed and linked to the current account.
required:
- owner_id
- claimed_at
properties:
owner_id:
type: string
format: uuid
description: Identifier of the owner that is now linked to the authenticated account.
example: 550e8400-e29b-41d4-a716-446655440000
claimed_at:
type: string
format: date-time
description: Timestamp at which the claim was confirmed.
example: '2026-06-20T14:30:00Z'
StartOwnerClaimResponse:
type: object
description: Response after starting an owner claim. The targeted owner receives the link by email.
required:
- frontend_url
- owner_email
properties:
frontend_url:
type: string
description: Frontend URL (containing the claim token) sent to the owner by email.
example: https://app.faireplace.com/owner-claim/3f8b1c2d-4e5f-6a7b-8c9d-0e1f2a3b4c5d
owner_email:
type: string
format: email
description: Email address of the owner the claim was started for.
example: owner@example.com
OwnerClaimError:
type: object
description: 'Error payload for the owner-claim endpoints.
Like the guest-signature flow, this uses a minimal `{ error_code, message }`
shape (NOT the global `Error` envelope), with generic messages on purpose
(anti-oracle / anti-leak).
'
required:
- error_code
- message
properties:
error_code:
type: string
example: OWNER_CLAIM_NOT_FOUND
message:
type: string
example: Demande introuvable.
ConfirmOwnerClaimBody:
type: object
description: 'Body for the confirm endpoint. An empty body is accepted: the confirmation
is derived from the authenticated JWT and the token in the path. The optional
field exists only to allow forward-compatible extension (e.g. consent flags).
'
properties: {}
additionalProperties: false
responses:
Unauthorized:
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
securitySchemes:
BearerAuth:
type: http
scheme: bearer
description: API key with fp_* prefix, passed as Bearer token
WorkerApiKey:
type: apiKey
in: header
name: X-API-Key
WorkerBearer:
type: http
scheme: bearer
bearerFormat: Worker