# Send and read JSON

Use [`ky`](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/ky#default) when you want to send a JSON request body and read the response as a typed value. The `json` option serializes the request body, and `.json<T>()` parses the response body and gives the result the TypeScript type `T`.

## Send a request and read its response

1. Pass the value to send in the `json` option; see [Add request headers](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/add-request-headers) for how Ky serializes it and sets `Content-Type`.
2. Call `.json<T>()` on the request to get a promise for the parsed response body, typed to the response shape your endpoint returns.

```ts
import ky from 'ky';

const main = async (): Promise<void> => {
	const createdUser = await ky.post('https://api.example.com/users', {
		json: {name: 'Ada'},
	}).json<{id: number; name: string}>();

	console.log(`Created ${createdUser.name} (${createdUser.id})`);
};

void main();
```

When the endpoint returns JSON with an `id` and `name`, `createdUser` has those typed fields and the log displays them. The type argument guides TypeScript; it does not validate the response at runtime. Keep it aligned with the endpoint's response contract.

## Options that matter

| Option or method | Type | Default | What it does |
| --- | --- | --- | --- |
| `json` | `unknown` | Not specified | Supplies this request's JSON payload; see [Add request headers](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/add-request-headers) for serialization and content-type behavior. |
| `.json<T>()` | `<JsonType = T>(schema?: undefined): Promise<JsonType>` | `T` defaults to `unknown` | Types the parsed response as the endpoint's response shape; it does not validate that shape at runtime. |

The body method also sets an appropriate `Accept` header. It throws an [`HTTPError`](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/ky-httperror#httperror) for a non-2xx response when HTTP errors are enabled, and `.json()` throws if the body is empty because it cannot be parsed.

## Pitfalls

- `ky.stop` makes the request resolve with `undefined`, so there is no response to inspect and body shortcuts such as `.json()` are incompatible with it. Throw from `beforeRetry` instead when the caller needs an error rather than a missing response.
- The type argument on `.json<T>()` is not runtime validation. If the response needs validation, use the approach in [Validate JSON responses](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/validate-json-responses).

## Related

- [Ky quick start](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/ky-quick-start)
- [Add request headers](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/add-request-headers)
- [Ky errors and validation](https://bench-ky-6l.atloria.app/p/bench-ky-6l-QSDF7DxJ6h/developer/ky-errors-and-validation)
