> For the complete documentation index, see [llms.txt](https://docs.medicare.healthsherpa.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.medicare.healthsherpa.com/api-reference/version-2-oauth/authentication.md).

# Authentication

The HealthSherpa for Medicare Partner API v2 uses **OAuth 2.0** **Authorization Code** flow for authentication.

**Production**

<table><thead><tr><th width="109.37890625">Endpoint</th><th width="131.421875">URL</th><th width="559.421875"></th></tr></thead><tbody><tr><td>Production</td><td>Authorization:</td><td><code>https://medicare.healthsherpa.com/oauth/authorize</code></td></tr><tr><td> </td><td>Token: </td><td><code>https://medicare.healthsherpa.com/oauth/token</code></td></tr><tr><td>Staging</td><td>Authorization:</td><td><code>https://medicare-staging.healthsherpa.com/oauth/authorize</code></td></tr><tr><td></td><td>Token: </td><td><code>https://medicare-staging.healthsherpa.com/oauth/token</code></td></tr></tbody></table>

### 1. Redirect User to Authorization Endpoint

Direct the user to:

```
https://medicare.healthsherpa.com/oauth/authorize?
client_id=YOUR_CLIENT_ID&
redirect_uri=YOUR_REDIRECT_URI&
response_type=code&
scope=partner_api_v2
```

**Parameters:**

* `client_id` (required): Your application's Client ID
* `redirect_uri` (required): Must match the URIs registered with HealthSherpa
* `response_type` (required): Always `code`
* `scope` (required): `partner_api_v2` - grants access to the Partner API v2

### **2. User Authorizes Your Application**

The user will see a consent screen asking to authorize your application. Upon approval, they are redirected to your `redirect_uri` with an authorization code:

```
YOUR_REDIRECT_URI?code=AUTH_CODE&state=STATE_VALUE
```

### **3. Exchange Authorization Code for Access Token**

Your server exchanges the authorization code for an access token:

```
curl -X POST https://medicare.healthsherpa.com/oauth/token
-H "Content-Type: application/x-www-form-urlencoded"
-d "grant_type=authorization_code"
-d "code=AUTH_CODE"
-d "client_id=YOUR_CLIENT_ID"
-d "client_secret=YOUR_CLIENT_SECRET"
-d "redirect_uri=YOUR_REDIRECT_URI"
```

**Response**:

```
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "def50200b7a9c3e4f1d2a6b8c9e0f123456789abcdef...",
  "scope": "partner_api_v2"
}
```

**Parameters**:

* `access_token`: Use this token to make API requests
* `token_type`: Always Bearer
* `expires_in`: Token lifetime in seconds, applies to the access token
* `refresh_token`: Use this token to obtain a new access token
* `scope`: Granted permissions, always "partner\_api\_v2"

### **4. Use the Access Token**

Include the access token in the Authorization header of your API requests:

{% code overflow="wrap" %}

```bash
curl https://api.medicare.healthsherpa.com/v2/contacts \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"contact": {"external_id": "CRM123", "first_name": "John", "last_name": "Doe"}}'
```

{% endcode %}

### 5. Refresh Tokens

When your access token expires, use the refresh token to get a new one :

```
curl -X POST https://medicare.healthsherpa.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=YOUR_REFRESH_TOKEN" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"
```

**Response:**

```
{
  "access_token": "NEW_ACCESS_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "NEW_REFRESH_TOKEN",
  "scope": "partner_api_v2"
}
```

Refresh tokens are rotated: when refreshing, store the newly returned `refresh_token` and discard the previous one.

***

### Troubleshooting

#### Invalid or Expired Token

```
{
  "error": {
    "message": "The access token is invalid.",
    "code": "invalid_token"
  }
}
```

**Response**: 401 Unauthorized

**Solution**: Obtain a new access token by repeating the OAuth flow.

#### Missing Authorization Header

```
{
  "error": {
    "message": "Missing authorization header",
    "code": "missing_authorization"
  }
}
```

**Response**: 401 Unauthorized

**Solution**: Include the Authorization: Bearer YOUR\_ACCESS\_TOKEN header in all requests.

#### Who can update a contact?

Update is owner-only. The contact must be assigned to the agent whose credentials are on the request. Being in the same agency as the owner is not enough. Full Book access in HealthSherpa is also not enough – that permission applies in the app, not on this API.

If the id exists but belongs to another agent, the API returns `404` with `resource_not_found`. That is the same response as a missing or unknown id. There is no separate error for “owned by someone else.”

***

### Security Best Practices

* Store Client Secret securely (use environment variables or secrets management)
* Use HTTPS for all requests
* Validate redirect URIs
* Rotate access tokens regularly
* Use short-lived access tokens
* Store tokens securely on your backend (never in frontend code)
