# Sign in with Pidgeon

> Every sign in with pidgeon endpoint, generated from the API's own schemas.

Base URL `https://pidgeon.ai/api/v1`. Every request carries `Authorization: Bearer pgn_live_…`. The machine-readable version of this page is https://pidgeon.ai/openapi.json.

## POST /sign-ins

Approve a sign-in as your address

Sign in with Pidgeon, from the agent’s side. An app gave the agent an authorization URL; post it here with a key that can **send** as the address, and get back the app’s callback with a one-use code. Open `redirect_url` yourself, within a minute, in the session that started the sign-in: whoever opens it is the one signed in. Name the address in `address` when the URL does not (`login_hint`). The key goes to Pidgeon only, never to the app. A key that can only read, or that does not reach the address, is refused as a send would be.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | no | Any string unique to this attempt, reused on its retries. A repeat with the same key and the same request returns the first answer with `Idempotent-Replay: true` and does nothing — no second email. The same key with a different request is a `409`. Kept for 24 hours; a failure is not kept, so a retry after one runs. |

**Body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `url` | string | yes | Where we POST. HTTPS, and it has to answer within a few seconds. |
| `address` | string | no | A whole address — the local part and the domain in one. An alternative to the other two. |

**Responses**

- `201` The callback to open.
- `400` The request is not valid. `error.field` names the input at fault when there is one.
- `401` No API key, or one that is not valid.
- `403` Refused. `error.code` says why: `forbidden` when this key may not do this or the account is on hold, `abuse_blocked` when a limit says no.
- `404` No such resource, or one this key cannot reach. The two answer the same, so treat a 404 as “not available to you” rather than “does not exist”.
- `409` Nothing was done by this call. `error.code` says which: `idempotency_in_progress` when the first request with this `Idempotency-Key` has not answered yet (wait `Retry-After` seconds and send it again), `idempotency_mismatch` when the key was used with a different request (use a new key).
- `429` Rate limited. `X-RateLimit-Reset` says when to retry.
- `500` Something went wrong on our side. Retry; if it keeps happening, tell us.
- `503` Something this needs is not answering right now. Retry in a moment.
- `504` Test mode only: `Pidgeon-Test-Fail: drop` dropped the answer (`test_dropped`). The request was done; retry it with the same `Idempotency-Key` to get the first answer.
