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

# Date & time

> UTC ISO 8601 timestamps, the ±10-second request-signing tolerance, and clock synchronization.

The BlooBank API uses a single time representation everywhere: **UTC ISO 8601 with millisecond precision**. There are no time zones in the API contract — the burden of localization sits on your client.

## Timestamps in responses

Every timestamp returned by the API is formatted:

```
YYYY-MM-DDTHH:mm:ss.sssZ
```

Examples:

```
2026-01-15T10:30:00.000Z
2026-01-15T10:31:24.512Z
```

The trailing `Z` (denoting UTC) is **always** present. The API never emits offsets like `-03:00`.

### Parsing

All mainstream languages parse this format natively:

| Language   | Idiom                                                                          |
| ---------- | ------------------------------------------------------------------------------ |
| JavaScript | `new Date(response.createdAt)`                                                 |
| Python     | `datetime.fromisoformat(response['createdAt'].replace('Z', '+00:00'))` (3.10+) |
| Go         | `time.Parse(time.RFC3339Nano, response.CreatedAt)`                             |
| Java       | `OffsetDateTime.parse(response.getCreatedAt())`                                |
| Rust       | `chrono::DateTime::parse_from_rfc3339(&response.created_at)`                   |

### Display

Format with the user's locale on the **client side**:

```ts theme={"dark"}
new Intl.DateTimeFormat('pt-BR', { dateStyle: 'long', timeStyle: 'medium', timeZone: 'America/Sao_Paulo' })
  .format(new Date(response.createdAt));
// "15 de janeiro de 2026 07:30:00"
```

## Timestamps in requests

Most request bodies do not carry timestamps — those are server-assigned. The single exception is the signed `X-Access-Timestamp` header carrying the request time.

### `X-Access-Timestamp`: milliseconds, not seconds

The signing protocol uses **Unix epoch milliseconds**, not seconds. A 2026-era timestamp is 13 digits, not 10:

```
1736553600123     ✓ milliseconds (correct)
1736553600        ✗ seconds (wrong — returns TIMESTAMP_INVALID)
```

## Clock-skew tolerance: ±10 seconds

The Access Protocol rejects any request whose `X-Access-Timestamp` is more than **±10 seconds** from server time. This is tighter than typical cloud SDKs (which allow minutes), and it is non-negotiable.

<Warning>
  **Run NTP on every host that signs requests.** Hosts without time synchronization will see intermittent `TIMESTAMP_SKEW_EXCEEDED` (HTTP 401) errors that look random to your application logs.
</Warning>

### Why so strict?

Tight clock-skew tolerance reduces the window in which a captured request can be replayed. Combined with the 1-hour deduplication of `X-Access-Request-Id`, the protocol is robust against replay attacks without requiring nonce challenges or session tokens.

### Common failure modes

| Symptom                                       | Cause                                                                   | Fix                                                                  |
| --------------------------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `TIMESTAMP_INVALID` (HTTP 400)                | Sent seconds instead of milliseconds.                                   | Multiply by 1000.                                                    |
| `TIMESTAMP_SKEW_EXCEEDED` (HTTP 401)          | Host clock drifted.                                                     | Enable `chronyd` / `ntpd`; verify with `chronyc tracking`.           |
| Random intermittent `TIMESTAMP_SKEW_EXCEEDED` | NTP refresh interval too long, or virtualized hosts with paused clocks. | Force a re-sync (`chronyc makestep`); check VM clock-drift settings. |
| `TIMESTAMP_SKEW_EXCEEDED` only at deploy      | Generating the timestamp at code-build time, not request-send time.     | Read the clock **once per request**, immediately before signing.     |

### Server time as a fallback

If you cannot run NTP (e.g., shared CI runners), you can approximate by reading server time once and computing an offset. The server time is conveyed in the `Date` response header on every response — including error responses — so you can extract it from a previous call.

```ts theme={"dark"}
const serverDate = new Date(response.headers.get('Date')); // RFC 7231 HTTP-date format
const offsetMs = serverDate.getTime() - Date.now();
// Use offsetMs as a correction term for subsequent requests
```

This is a **last-resort fallback**, not a substitute for proper NTP.

## Time zones

The API contract has no notion of time zones. Every absolute moment is UTC. Convert at the edges:

* **Server → User**: UTC timestamp → user's local time on the client.
* **User → Server**: parse user input in their local timezone → UTC ISO 8601 → send.

For filtering by date ranges, convert your user's date selection to UTC before constructing the `filter` expression:

```ts theme={"dark"}
const startOfDay = new Date('2026-01-15T00:00:00-03:00').toISOString();
// "2026-01-15T03:00:00.000Z"

const filter = `createdAt>=${startOfDay}`;
```

## Next

<CardGroup cols={2}>
  <Card title="Sign a request" icon="signature" href="/get-started/authentication/sign-request">
    Where `X-Access-Timestamp` fits in the canonical request.
  </Card>

  <Card title="Filtering" icon="filter" href="/get-started/concepts/filtering">
    How to filter list endpoints by date ranges.
  </Card>
</CardGroup>
