# Create a session

> Create a Connect session from your server with the categories you need, then send the patient to its url.

## Send the request

```bash
curl -X POST "https://api.finchnode.com/api/v1/connect/sessions" \
  -H "Authorization: Bearer $FINCHNODE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: signup-user_123-1" \
  -d '{
    "externalId": "user_123",
    "categories": ["medications", "labs", "allergies"],
    "returnUrl": "https://example.com/connected"
  }'
```

The response is `201` with the session and its `url`. Store the session `id` with your own user, then send the patient to `url`.

## Fields

Every field is optional. Send only these:

| Field | What to send |
| --- | --- |
| `externalId` | Your own reference for this user, up to 200 characters. It comes back on the session and in webhooks, so use an opaque ID, never an email, name, or health detail. |
| `categories` | The [categories](/docs/records/record-model) you need. Each must be on your application's list. Defaults to that list. |
| `syncMode` | `one-time` or `continuous`. Defaults to your application's setting. |
| `durationDays` | How long the share lasts: a whole number from 1 to 730. Defaults to 365. |
| `returnUrl` | Where the patient can go when they finish, up to 2,048 characters. |

The purpose patients see comes from your application settings, not the request.

## Ask for less

Request only the categories your product uses. Patients see the list on the consent screen, and a shorter list is easier to approve.

## Continuous sync

`continuous` keeps records up to date after the first import. Your application must be set to continuous, or the request returns `403`. Even then, a share ends up one-time if the patient doesn't opt in or the health system doesn't allow ongoing access. The [consent receipt](/docs/resources/glossary#consent-receipt) behind the share has a `syncMode` that says which you got. See [Freshness, partial and stale records](/docs/records/freshness).

## Return URL

- Use an `https` URL on your own domain. In the sandbox, `http://localhost` and `http://127.0.0.1` also work.
- Don't use a URL with a username or password in it.
- FinchNode adds nothing to it and drops any `#fragment`. Arriving there doesn't mean the patient finished. See [After the patient connects](/docs/connect/after-the-patient-connects).

## Retry safely

Send an `Idempotency-Key` header with each logical request, up to 200 characters. Repeating the same key and body returns the original session with `Idempotent-Replayed: true`. The same key with a different body returns `409 idempotency_conflict`.

## Cancel a session

If your user gives up or logs out, cancel the session so its link stops working:

```bash
curl -X POST "https://api.finchnode.com/api/v1/connect/sessions/$SESSION_ID/cancel" \
  -H "Authorization: Bearer $FINCHNODE_API_KEY"
```

A completed session returns `409 session_completed`, and an expired one `410 session_expired`.

## Errors to handle

| Response | When | Fix |
| --- | --- | --- |
| `400 invalid_request` | A field is unknown or out of range. | Read `error.message` for the field. |
| `403 invalid_request` | A category isn't on your application's list, or `continuous` on a one-time application. | Change the application in the console, or the request. |
| `400 invalid_idempotency_key` | The key is over 200 characters. | Shorten it. |
| `409 idempotency_conflict` | You reused a key with a different body. | Use a new key for a new request. |
| `403 production_not_enabled` | A production key on an application that isn't live yet. | Turn on production, or use a sandbox key. |

The full list is on [Errors](/docs/resources/errors).
