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

# Share secrets

> Hand a value to someone who has no Sink account, with an expiry and a view cap.

A share link hands out secret values to someone outside the workspace — a contractor, a support engineer, a colleague who has not signed up yet. The link carries its own expiry and a view budget, and stops working when either runs out.

<Info>
  Secure sharing is a paid capability. On a plan without it the create call answers `402`. See [Plans and limits](/guides/plans).
</Info>

## Create a link

```http theme={null}
POST /secrets/{workspace_id}/{team_id}/{project_id}/{environment_id}/share
```

```json theme={null}
{
  "secret_ids": ["6f1c…", "9ab2…"],
  "expires_in_minutes": 60,
  "max_views": 1
}
```

<ParamField body="secret_ids" type="UUID[]">
  Which secrets to share. Omit the field entirely to share every secret in the environment. An empty array is rejected, and unknown ids come back as a `404` listing them.
</ParamField>

<ParamField body="expires_in_minutes" default="60" type="integer">
  Lifetime of the link, between 1 and 10080 (seven days).
</ParamField>

<ParamField body="max_views" default="1" type="integer">
  How many times the link may be redeemed, between 1 and 100. The default is single-use.
</ParamField>

The response carries the link to send:

```json theme={null}
{
  "token": "…",
  "url": "https://usesink.co/share/…",
  "expires_at": "2026-08-21T18:30:00Z",
  "max_views": 1,
  "secret_count": 2
}
```

## What the recipient sees

Opening the URL loads a page that reports how many secrets are behind the link, when it expires and how many views remain — **without spending one**. Chat clients unfurl links and browsers prefetch them, and neither should burn the recipient's only view.

The values are only released when the recipient actively asks for them, which the page does by POSTing back to the same path.

<Note>
  Redeeming is `POST /share/{token}`, not `GET`. A bare `GET` is always safe to follow.
</Note>

```bash theme={null}
curl -X POST https://usesink.co/share/<token>
```

```json theme={null}
{
  "secrets": [
    { "key": "DATABASE_URL", "value": "postgres://…", "description": "Primary DB" }
  ],
  "views_remaining": 0,
  "expires_at": "2026-08-21T18:30:00Z"
}
```

Redemption is unauthenticated by design: possession of the token is the credential. When the last view is spent the link is deleted immediately.

| Status | Meaning                                                               |
| ------ | --------------------------------------------------------------------- |
| `200`  | Values returned; `views_remaining` says what is left.                 |
| `404`  | The token is unknown or has expired.                                  |
| `410`  | The view budget is already spent, or the underlying secrets are gone. |
| `503`  | The share store is temporarily unavailable.                           |

## What gets recorded

Creating a link writes a `SHARED` audit entry against every secret in it, attributed to the member who created it. Each redemption writes an `ACCESSED` entry against the same secrets — also attributed to the sharer, since the recipient is anonymous by construction. Both show up in [the secret's log](/security/audit).

## Practical limits

Share links live in a store with a TTL, so they disappear on their own even if nobody opens them. The two public routes are rate limited per calling address — 30 page views and 10 redemptions a minute — so a leaked link cannot be walked through quickly from one machine.

<Warning>
  A share link is a bearer credential in a URL. Anyone who sees the message it was sent in can spend a view. Keep `max_views` at 1 and the expiry short unless you have a reason not to, and rotate the value afterwards if the channel was not private.
</Warning>
