# Request and Response Format

https://dev.wisecp.com/es/request-and-response-format

One envelope, one set of status codes and one pagination shape, on every endpoint of every surface.

## Overview

The shape of a call does not change from resource to resource. If you can read one response you can read all of them, and error handling written once keeps working as your integration grows.

Two rules carry most of it. A successful answer puts its payload under `data`, and a failed one puts a machine-readable code under `error`. The HTTP status always agrees with which of the two arrived.

## Reference

### The Request

Send JSON with a `Content-Type: application/json` header. A form-encoded POST is accepted as well, which helps when a client cannot set the header. Filters, sorting and paging travel in the query string on every method.

- **Authorization: Bearer**: The API key. `X-Api-Key` is the fallback for clients that cannot set this one.
- **Content-Type**: Set it to `application/json` when the body is JSON. Without it the body is read as form fields.
- **Idempotency-Key**: Optional, POST only, 8 to 191 characters. A repeat of the same key returns the stored answer instead of doing the work twice.
- **X-Http-Method-Override**: For callers behind a proxy that allows only GET and POST. The value replaces the method.

### The Envelope

Success carries `data`, plus `meta` when there is anything to say about the payload. Failure carries `error` with a stable `code`, a human message and, on validation failures, a `details` map naming the fields.

```json
{ "data": { "id": 42, "email": "ada@example.com" } }

{ "data": [ ], "meta": { "total": 318, "page": 2, "limit": 25, "next_page": 3 } }

{ "error": { "code": "validation_failed", "message": "Email is not valid.",
             "details": { "email": "invalid_format" } } }
```

Branch on the key, not on the text. `code` is part of the contract and stays put; `message` is written for a human reading a log and may be reworded.

### Status Codes

- **200 · 201**: Done. Creation answers with 201 and returns the new record.
- **401**: No key, or one the installation does not know. Fix the credential; a retry will not help.
- **403**: The key is known but not allowed here: wrong surface, missing permission, or a write while demo mode is on.
- **404**: No such endpoint, or no such record for this key. On the client surface a record owned by someone else answers the same way.
- **409**: A request with the same `Idempotency-Key` is still running. Wait and retry.
- **413**: The body is past the server upload limit. It never reached the resource, so nothing was saved.
- **422**: The input was understood and refused. `details` names the fields.
- **429**: Too many requests. Honour `Retry-After`.
- **500**: Something failed on the far side. The detail is kept in the operator's log, not in your response.

### Pagination

List endpoints take `page` and `limit` in the query string. `limit` defaults to 25 and is capped at 100, so asking for more silently gives you 100. Walk pages with `meta.next_page`, which is `0` on the last one.

Offset paging is the v1 contract. Cursor paging exists only where the data is a timeline, such as ticket messages, and those endpoints document their own cursor fields.

### Response Headers

Every credentialed answer reports the state of your budget, so you can pace yourself without guessing.

- **X-RateLimit-Limit**: Requests allowed in the current one-minute window.
- **X-RateLimit-Remaining**: What is left of it.
- **X-RateLimit-Reset**: Unix time when the window turns over.
- **Idempotency-Replayed**: Present when the answer came from storage rather than fresh work.

## Example

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/clients' \
     -H 'Authorization: Bearer wak_...' \
     -H 'Content-Type: application/json' \
     -H 'Idempotency-Key: signup-8f21c0' \
     -d '{"name":"Ada","surname":"Lovelace","email":"ada@example.com"}'
# 201  {"data":{"id":91,...}}

# the same call again returns the same body, and does not create a second client
# 201  Idempotency-Replayed: true
```

## Pitfalls

> **Totals live under meta, not at the top**
> 
> A list answer keeps its count at `meta.total`. Reading `total` from the root gives you nothing and no error, which reads as an empty result set. The same goes for `page` and `limit`.

> **Demo mode refuses every write**
> 
> While an installation is in demo mode, POST, PUT, PATCH and DELETE come back as `403 demo_mode` before any resource is reached. Reads keep working, so a demo stays browsable through the API. An integration that fails only on writes is worth checking against this first.

## Related Articles

- [The WISECP API](https://dev.wisecp.com/en/the-wisecp-api)
- [API Authentication and Permissions](https://dev.wisecp.com/en/api-authentication-and-permissions)
- [API Resources](https://dev.wisecp.com/en/api-resources)
