> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gridbeds.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Owner connect

> A host links its Gridbeds listings to an account on your side, with a signed single-use token and no contact details shared.

<Warning>
  **Not served yet.** This page describes the final contract, version `1.0.0`. Until the sandbox opens with the first test key, try it against a mock of the contract ([Testing](/en/distribution-api/testing)).
</Warning>

Owner connect lets a host link its Gridbeds listings to an account on your side. Gridbeds shares no e-mail address or other contact detail of the host to make it happen: nothing about the host reaches you except through this action. Confirming and removing a connection needs the scope `write:listings`.

## Before you start

Register your redirect URL with Gridbeds: the public HTTPS page a host's browser posts its token to. Register it once for each environment, because the sandbox and production each keep their own record of your channel: your staging site on the sandbox, your live site in production. `GET /channel` answers the one of the key's environment in `owner_connect.redirect_url`. It is `null` until registered, and hosts cannot start a connection to your channel until then.

## The flow

<Steps>
  <Step title="The host starts">
    The host starts connecting its account with your channel in Gridbeds.
  </Step>

  <Step title="Its browser posts the token to you">
    Gridbeds answers the host with an HTML form that its browser submits at once to your redirect URL: a form POST (`application/x-www-form-urlencoded`) whose only field is `token`. The token never appears in a URL, a server log, the browser history or a `Referer`.
  </Step>

  <Step title="You verify it and keep it server-side">
    Verify the token as below and keep it on your server, then answer with a `303` to one of your own pages. The POST is cross-site, so the browser does not send your cookies marked `SameSite=Lax` or `Strict` with it; on your own page the host's session is available again. For an invalid, expired or replayed token, show a page saying the link failed: the host can start again from Gridbeds.
  </Step>

  <Step title="The host signs in and confirms">
    Let the host sign in or sign up on your side (the host types their own e-mail address there if you need one), then ask the signed-in host to confirm the link on your own page, showing the owner's `display_name`.
  </Step>

  <Step title="You bind it and confirm">
    Bind the token's `sub`, an owner id you hold from `GET /owners`, to that account, and send the token to `PUT /owners/{owner_id}/connection`. The owner's `connected_at` is set (`owner.updated`), and the host sees the account connected in Gridbeds.
  </Step>
</Steps>

**Never bind on the POST alone.** Any site can make a browser submit a form, so a token posted without the host's confirmation could link someone else's owner to the account that happens to be signed in.

## The token

The token is a JWS in compact serialization (RFC 7515; a JWT, RFC 7519) signed with ES256.

| Part | |
| - | - |
| Header | `alg` `ES256`, `typ` `owner-connect+jwt`, `kid` the signing key. |
| `iss` | The API's origin: `https://api.gridbeds.com`, or `https://staging-api.gridbeds.com` on the sandbox. |
| `aud` | Your channel: the `channel` of `GET /channel`. |
| `sub` | The owner id. |
| `property_ids` | The ids of that owner's properties distributed to you when the host started. |
| `iat` | When it was issued. |
| `exp` | When it expires: at most 300 seconds after `iat`. |
| `jti` | A random single-use id of 128 bits. |
| `locale` | The host's interface language (BCP 47). It may be absent. |

Verify all of it before trusting any claim:

* **The signature**, with the key named by `kid` in `GET /owner-connect/keys`: a JWKS (RFC 7517) of EC P-256 public keys for ES256, public, needing no key and limited per client address. Cache it as its `Cache-Control` says, and fetch it again when a token names a `kid` you do not hold. A new signing key is published at least 24 hours before it signs, and a retired one stays published 24 hours after it stops.
* **`alg` exactly `ES256` and `typ` exactly `owner-connect+jwt`**, refusing `none` and every other value (RFC 8725).
* **`iss` and `aud`** as above. A token minted in one environment is verified against that environment's `iss` and keys only.
* **`exp` in the future and `iat` not in the future**, with at most 60 seconds of clock skew.
* **`sub` an owner distributed to you.**

## Two deadlines

* **`exp` bounds the browser's leg.** It is at most 300 seconds after `iat`, and your redirect page accepts the token only before it.
* **The confirmation may come later**, because the host may have to sign up first. `PUT /owners/{owner_id}/connection` accepts an unconfirmed token until 3600 seconds after its `iat`, and only from the channel named in its `aud`, with that channel's own key. Keep the verified token server-side meanwhile, never in a page or a URL.

## Replay

A token is single use. Keep every `jti` you accept until its `exp`, and refuse one you have seen. Gridbeds binds a token to the one connection it confirms: confirming it again for the same owner answers the same connection, and any other use is refused.

## Confirm and remove a connection

```http theme={null}
PUT /api/v1/distribution/owners/own_63g5d4zsqj809bf5rwekga54a5/connection HTTP/1.1
Host: api.gridbeds.com
Authorization: Bearer gbd_live_…
Content-Type: application/json

{"token": "eyJ…"}
```

The token's `sub` must be this owner, its `aud` your channel and its `iat` at most 3600 seconds ago. The answer is the connection, `{owner_id, connected_at}`. A refusal is `400` `invalid_parameters` with `errors[].pointer` `/token` and `errors[].code` `token_invalid`, `token_expired`, `token_owner_mismatch` or `token_used`.

When the host disconnects the account on your side, send `DELETE /owners/{owner_id}/connection`: the owner's `connected_at` becomes `null` (`owner.updated`), and deleting a connection that does not exist answers `204` as well. `connected_at` also becomes `null` when the host disconnects in Gridbeds, which reaches you as an `owner.updated`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.