# blue.hearth.entitlement

> Published by [hearth.blue](https://lexicon.garden/identity/did:web:hearth.blue)

✓ This is the authoritative definition for this NSID.

## Links

- [View on Lexicon Garden](https://lexicon.garden/lexicon/did:web:hearth.blue/blue.hearth.entitlement)
- [Documentation](https://lexicon.garden/lexicon/did:web:hearth.blue/blue.hearth.entitlement/docs)
- [Examples](https://lexicon.garden/lexicon/did:web:hearth.blue/blue.hearth.entitlement/examples)

## Definitions

### `blue.hearth.entitlement`

**Type**: `record`

Proof that a subscriber currently holds a tier. This is the record attested.network deliberately leaves undefined: its payment records prove a payment happened but carry no expiry, revocation or status, so they cannot answer 'is this subscription active right now'. Lives in the SUBSCRIBER's repository, alongside the payment record that granted it. Entitlements are short-lived and RENEWED, never long-lived and revoked: each successful billing cycle writes a fresh record, so cancellation is the observable absence of a renewal rather than a revocation list a verifier must fetch and trust.

**Key**: `tid`

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `tier` | `ref` → `com.atproto.repo.strongRef` | Yes | The blue.hearth.tier record granted. A strongRef, so the tier's terms at grant time are pinned by CID and cannot be edited out from under an existing entitlement. |
| `status` | `string` | Yes | active is the normal case and the only one written on renewal. cancelled is optional and terminal, written when a subscriber cancels, so propagation is immediate rather than waiting out validUntil. lapsed marks a known payment failure. A verifier must still check validUntil against the current time: status alone is never sufficient, since an active record whose window has passed is expired. Closed rather than knownValues on purpose — an un-enumerated status is exactly the defect in the spec this record exists to fix, and a verifier that meets a status it does not know cannot safely decide either way, so such a record should fail validation rather than reach the verifier at all. The cost is real: adding a value later (say paused) is a lexicon revision that older validators will reject. |
| `creator` | `string` (did) | Yes | The creator this entitlement is for. Derivable from tier's AT-URI, but stated explicitly so a verifier answering 'does X subscribe to Y' can filter without dereferencing every tier record. |
| `payment` | `ref` → `com.atproto.repo.strongRef` | Yes | The network.attested.payment.recurring record that granted this. Normally in the same repository, since both the payment record and the entitlement live with the subscriber. |
| `createdAt` | `string` (datetime) | Yes |  |
| `validFrom` | `string` (datetime) | Yes |  |
| `signatures` | `array` | No | badge.blue attestations over this record: the creator's proof and the broker's. Left as unknown because badge.blue defines both the inline (ECDSA in-record) and remote (strongRef to a proof record) shapes, and pinning either here would break the other. An entitlement with no signatures is worthless to a verifier and must not be trusted. |
| `validUntil` | `string` (datetime) | Yes | End of the billing period PLUS a grace window. The grace exists because recurring payments bill on anniversary dates with automatic retry: without slack, a card merely awaiting retry reads as lapsed to every independent verifier, and hearth could not correct that, because verifiers do not call hearth. |

## Raw Schema

```json
{
  "id": "blue.hearth.entitlement",
  "defs": {
    "main": {
      "key": "tid",
      "type": "record",
      "record": {
        "type": "object",
        "required": [
          "creator",
          "tier",
          "payment",
          "validFrom",
          "validUntil",
          "status",
          "createdAt"
        ],
        "properties": {
          "tier": {
            "ref": "com.atproto.repo.strongRef",
            "type": "ref",
            "description": "The blue.hearth.tier record granted. A strongRef, so the tier's terms at grant time are pinned by CID and cannot be edited out from under an existing entitlement."
          },
          "status": {
            "enum": [
              "active",
              "cancelled",
              "lapsed"
            ],
            "type": "string",
            "description": "active is the normal case and the only one written on renewal. cancelled is optional and terminal, written when a subscriber cancels, so propagation is immediate rather than waiting out validUntil. lapsed marks a known payment failure. A verifier must still check validUntil against the current time: status alone is never sufficient, since an active record whose window has passed is expired. Closed rather than knownValues on purpose — an un-enumerated status is exactly the defect in the spec this record exists to fix, and a verifier that meets a status it does not know cannot safely decide either way, so such a record should fail validation rather than reach the verifier at all. The cost is real: adding a value later (say paused) is a lexicon revision that older validators will reject."
          },
          "creator": {
            "type": "string",
            "format": "did",
            "description": "The creator this entitlement is for. Derivable from tier's AT-URI, but stated explicitly so a verifier answering 'does X subscribe to Y' can filter without dereferencing every tier record."
          },
          "payment": {
            "ref": "com.atproto.repo.strongRef",
            "type": "ref",
            "description": "The network.attested.payment.recurring record that granted this. Normally in the same repository, since both the payment record and the entitlement live with the subscriber."
          },
          "createdAt": {
            "type": "string",
            "format": "datetime"
          },
          "validFrom": {
            "type": "string",
            "format": "datetime"
          },
          "signatures": {
            "type": "array",
            "items": {
              "type": "unknown"
            },
            "description": "badge.blue attestations over this record: the creator's proof and the broker's. Left as unknown because badge.blue defines both the inline (ECDSA in-record) and remote (strongRef to a proof record) shapes, and pinning either here would break the other. An entitlement with no signatures is worthless to a verifier and must not be trusted."
          },
          "validUntil": {
            "type": "string",
            "format": "datetime",
            "description": "End of the billing period PLUS a grace window. The grace exists because recurring payments bill on anniversary dates with automatic retry: without slack, a card merely awaiting retry reads as lapsed to every independent verifier, and hearth could not correct that, because verifiers do not call hearth."
          }
        }
      },
      "description": "Proof that a subscriber currently holds a tier. This is the record attested.network deliberately leaves undefined: its payment records prove a payment happened but carry no expiry, revocation or status, so they cannot answer 'is this subscription active right now'. Lives in the SUBSCRIBER's repository, alongside the payment record that granted it. Entitlements are short-lived and RENEWED, never long-lived and revoked: each successful billing cycle writes a fresh record, so cancellation is the observable absence of a renewal rather than a revocation list a verifier must fetch and trust."
    }
  },
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1
}
```
