---
title: "Rotating heartbeat — verifies + rotates the binding nonce, emits split-detection on mismatch"
method: POST
path: "/v1/license/heartbeat"
tags: ["License Binding"]
---

# Rotating heartbeat — verifies + rotates the binding nonce, emits split-detection on mismatch

`POST /v1/license/heartbeat`

## Request

- Base URL: `https://api.vendure.io` (the document declares no server; this is the origin it was published from)
- URL: `https://api.vendure.io/v1/license/heartbeat`
- Auth: none declared
- TypeScript: <https://skmtc.dev/vendure/apis/vendure-io-api-public/docs/v1/license/heartbeat/post.ts> (a function with typed inputs; its response is checked against the schema)

## Request body

- LicenseBindingHeartbeatDto
  - `projectToken` string, required: Signed project phone-home JWT
  - `bindingToken` string, required: Signed binding token from the last activate / heartbeat response

## Response `200`

- LicenseBindingEnvelopeDto
  - `body` LicenseBindingEnvelopeBodyDto, required
    - `kind` 'project_binding', required
    - `projectId` string, uuid, required
    - `instanceId` string, uuid, required
    - `jti` string, required: Rotating nonce — echo back on next heartbeat
    - `env` 'production' | 'staging' | 'uat' | 'dev', required: Deployment environment stamped on the project JWT the plugin presented. Mirrors the verified `env` claim so the plugin can log / expose the active env without re-parsing the project JWT. Prod is singleton per project; non-prod envs allow N concurrent ACTIVE seats.
    - `iat` number, required: Issued-at, unix seconds. Informational mirror of the JWS `iat` — trust the verified signature payload, not this field.
    - `exp` number, required: Expiry, unix seconds. The hub enforces this on the next heartbeat via a verifier-side `exp` check with ±30s clock-skew tolerance. Plugins SHOULD rotate well before this value — the expiry exists as a belt-and-braces defence against replay while the hub is paused, not as the primary freshness guarantee (that is the rotating `jti`).
  - `signature` string, required: Compact JWS signed with the project-JWT signing key

## Other responses

- `400`: Validation failed
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `409`: Conflict
- `500`: Internal server error

---

[API](https://skmtc.dev/vendure/apis/vendure-io-api-public.md) - [All operations](https://skmtc.dev/vendure/apis/vendure-io-api-public/llms.txt) - [OpenAPI document](https://skmtc.dev/vendure/apis/vendure-io-api-public/revisions/0747ce439f89?raw)
