---
title: "Status & live reports — Certificates for Laravel | Roundly"
description: "The CertificateStatus lifecycle and its transitions, registry status vs. cached live provider reports, and cache control."
url: https://roundly-consulting.com/open-source/docs/certificates-for-laravel/status
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Certificates for Laravel](https://roundly-consulting.com/open-source/docs/certificates-for-laravel.md)

# Status & live reports

Two status surfaces answer different questions. Certificates::status() reads the registry — the CertificateStatus of the certificate covering the domain (its own latest record, else a SAN certificate listing it), or null. Certificates::statusReport() asks the provider live and returns a CertificateStatusReport, cached per status\_cache.\*:

```php
Certificates::statusReport('app.example.com');               // cached
Certificates::statusReport('app.example.com', fresh: true);  // bypass + refresh
Certificates::for('app.example.com')->fresh()->statusReport();
```

```php
$report = Certificates::statusReport('app.example.com', driver: 'acme');

$report?->status;       // CertificateStatus
$report?->expiresAt;    // CarbonImmutable|null
$report?->issuer;       // ?string
$report?->serial;       // ?string
$report?->fingerprint;  // ?string
$report?->domains;      // list<string> — SANs
```

statusReport() returns null for a driver that cannot report status — null, or a custom driver without ReportsCertificateStatus.

## Caching

With status\_cache.enabled, each report is cached on status\_cache.store for status\_cache.ttl seconds under a key per driver and certificate name. fresh: true — or ->fresh() on the builder — re-queries the provider and refreshes the cached entry. issue() and renew() drop that certificate’s cached report, so the next statusReport() reads the new state instead of the one cached before the change. To drop an entry yourself, forget it on the resolver:

```php
use RoundlyConsulting\Certificates\Support\CachedStatusResolver;

app(CachedStatusResolver::class)->forget('acme', Certificates::certificateName('app.example.com'));
```

## The CertificateStatus enum

The model’s status column is cast to a string-backed enum with a native state machine:

| Case | Value | Colour | Can move to |
| --- | --- | --- | --- |
| `Pending` | pending | amber | Requested |
| `Requested` | requested | amber | Issued, Failed |
| `Issued` | issued | green | Renewing, Expired, Revoked |
| `Renewing` | renewing | amber | Renewed, Failed |
| `Renewed` | renewed | green | Renewing, Expired, Revoked |
| `Failed` | failed | red | Renewing — a failed row can be renewed again |
| `Expired` | expired | red | — (terminal) |
| `Revoked` | revoked | red | — (terminal) |

```php
use RoundlyConsulting\Certificates\Enums\CertificateStatus;

CertificateStatus::Issued->isActive();              // true
CertificateStatus::Revoked->isTerminal();           // true
CertificateStatus::Failed->isTerminal();            // false — a failed row can be renewed again
CertificateStatus::Requested->canTransitionTo(CertificateStatus::Issued); // true
CertificateStatus::Failed->canTransitionTo(CertificateStatus::Renewing);  // true
CertificateStatus::Issued->allowedTransitions();    // [Renewing, Expired, Revoked]
CertificateStatus::Issued->color();                 // 'green'
CertificateStatus::Issued->label();                 // 'Issued' (en), 'Vydaný' (sk)

CertificateStatus::toOptions();       // value => label, for selects
CertificateStatus::validationRule();  // 'in:pending,requested,issued,...'
```

isActive() is true for Issued and Renewed; isTerminal() for Expired and Revoked — only a fresh issue() revives those rows. Failed is not terminal: a failed issuance or renewal can be renewed again. The enum adopts enums-for-laravel’s Helpers trait, adding values(), labels(), options(), toOptions(), validationRule(), tryFromLabel() and more for admin UIs and validation.

label() reads certificates::messages.statuses.<value> in the current locale (Issued / Vydaný), and labels(), options(), toOptions() and tryFromLabel() read the same line. A locale the package ships no lines for gets the headline (Issued), where your JSON translations still apply.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/certificates-for-laravel.md)
