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

# POST /v1/messages

> Anthropic-compatible drop-in endpoint. Change one line in your existing @anthropic-ai/sdk code and everything works.

Anthropic-compatible drop-in endpoint. Change one line in your existing `@anthropic-ai/sdk` code and everything works. Requires the `ai:chat` scope.

## Migrating from Anthropic

```javascript theme={null}
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  baseURL: 'https://api.usehasp.com',  // ← only this line changes
  apiKey: 'hasp_api_live_...',
});
```

Request shape, response shape, streaming events, and tool use are Anthropic's exact wire format. Your existing code, types, and tooling continue to work.

## Request

```
POST https://api.usehasp.com/v1/messages
Authorization: Bearer hasp_api_live_...
Content-Type: application/json
```

The request body is identical to [Anthropic's Messages API](https://docs.anthropic.com/en/api/messages). Key fields:

| Parameter    | Type    | Description                                                                                                                                                                                       |
| ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`      | string  | HASP model ID. Anthropic identifiers (`claude-sonnet-4-6`, etc.) map straight through; any model in the [catalog](/ai-api/concepts/model-selection) — including OpenAI models — is also accepted. |
| `messages`   | array   | Conversation turns: `[{"role": "user", "content": "..."}]`                                                                                                                                        |
| `max_tokens` | integer | Required by Anthropic's spec.                                                                                                                                                                     |
| `stream`     | boolean | `true` for SSE, `false` for a single JSON response.                                                                                                                                               |
| `system`     | string  | System prompt.                                                                                                                                                                                    |
| `tools`      | array   | Tool definitions (same format as Anthropic).                                                                                                                                                      |

## Streaming events

When `stream: true`, the event stream uses Anthropic's exact wire format:

```
event: message_start
event: content_block_start
event: content_block_delta   (repeated)
event: content_block_stop
event: message_delta
event: message_stop
event: ping                  (keep-alive)
event: error                 (on failure)
```

This means libraries and utilities that parse Anthropic SSE streams work without modification.

## Compliance behavior

All HASP compliance checks apply — PHI Guard, BAA enforcement, credit metering — regardless of which endpoint you use. Compliance is a property of your organization, not the endpoint shape.

* **PHI Guard** runs on all messages. If `phi_mode=redact` (default), PHI is replaced with placeholders before the upstream call. If `phi_mode=block`, the request returns `403 PHI_BLOCKED` using the HASP error envelope.
* **BAA required.** No active BAA → `402 BAA_REQUIRED` on every request.
* **Credit metering.** Credits are deducted after each successful response. Exhausted credits → `402 AI_CREDITS_EXHAUSTED`.

## Native-only flags are rejected

Parameters that exist in the native `/v1/ai/chat` endpoint but not in Anthropic's wire format are **rejected with `400 UNSUPPORTED_PARAMETER`** rather than silently accepted:

* `store` — use `POST /v1/ai/chat` if you need stateless (no-content-storage) requests.
* Any other non-Anthropic field.

This keeps the contract honest — if you send `store: false` and get a 200 back, you might wrongly assume the content wasn't stored.

## Graduating to native features

Customers using `/v1/messages` can migrate endpoint-by-endpoint to `/v1/ai/chat` to gain:

* `store: false` for stateless requests
* PHI entity metadata in responses
* Run and conversation management

No breaking changes are required for the migration — the two endpoints are independent.

## Error codes

| Code                         | HTTP | Description                                                               |
| ---------------------------- | ---- | ------------------------------------------------------------------------- |
| `INVALID_API_KEY`            | 401  | Missing or revoked token                                                  |
| `BAA_REQUIRED`               | 402  | No active BAA                                                             |
| `AI_CREDITS_EXHAUSTED`       | 402  | Credit allotment exhausted                                                |
| `MISSING_SCOPE`              | 403  | Key lacks `ai:chat` scope                                                 |
| `PHI_BLOCKED`                | 403  | PHI detected and `phi_mode=block` is configured                           |
| `MODEL_ACCESS_DENIED`        | 403  | Requested model is not enabled for this org, or the identifier is unknown |
| `UNSUPPORTED_PARAMETER`      | 400  | Non-Anthropic parameter sent (e.g. `store`)                               |
| `RATE_LIMITED`               | 429  | RPM or daily limit exceeded                                               |
| `INFERENCE_UPSTREAM_FAILURE` | 502  | Upstream model provider error — retryable                                 |
