# Certificates

An MC4P certificate is a JSON-LD document that describes one product or one
image, plus a signed proof that Mintall issued it for a specific domain.

Both endpoints are public. Responses carry
`Cache-Control: public, max-age=86400`, so a crawler can cache a certificate
for a day.

## Fetch a product certificate

```bash
curl https://api.mintall.ai/api/v1/mc4p/products/$PRODUCT_ID/certificate
```

Mintall publishes the certificate as its own JSON-LD block on the product page,
alongside whatever product markup the store already emits. It identifies the
same product by `productID` and `url`.

```json
{
  "@context": ["https://schema.org", { "mintall": "https://mintall.ai/ns/" }],
  "@type": "Product",
  "productID": "...",
  "url": "https://merchant.example/products/pendant",
  "mintall:issuedFor": { "domain": "merchant.example", "productID": "..." },
  "mintall:status": { "canonicalSource": "..." },
  "mintall:images": [...],
  "mintall:trust": { "certifiedAssets": 4, "totalAssets": 5, "coveragePercent": 80 },
  "verification": { "verifyEndpoint": "...", "hasSignature": true },
  "proof": { "type": "JsonWebSignature2020", "jwt": "eyJ...", "algorithm": "RS256" }
}
```

`mintall:trust` reports coverage, not a score. An aggregate the issuer computes
about itself isn't independently checkable, so the block carries only the two
counts and their ratio — all three
[signed into the JWT](/api/verifying#signed-claims), so a verifier can confirm
them.

## Fetch an asset certificate

```bash
curl https://api.mintall.ai/api/v1/mc4p/assets/$ASSET_ID/certificate
```

An asset certificate is the full expansion of one entry in the product
certificate's `mintall:images[]` array, as a `mintall:`-namespaced
`ImageObject`. It adds `mintall:contentCredentials` (the C2PA manifest summary
and hashes) and `mintall:nft` where one exists.

## When a certificate has no `proof`

Every response is one of three outcomes:

```js
if (res.status === 404) {
  // Not served by Mintall: disabled, deleted, or never ingested.
} else if (!certificate.proof) {
  // Known to Mintall, not currently publishing trust data. Not a failure.
} else {
  // Signed by Mintall and verifiable.
}
```

A product that exists but is not active — the merchant has visibility off, or
the product sits outside their plan capacity — returns 200 with identity fields
only. `mintall:images`, `mintall:trust`, `verification`, and `proof` are
omitted:

```json
{
  "@context": ["https://schema.org", { "mintall": "https://mintall.ai/ns/" }],
  "@type": "Product",
  "productID": "...",
  "url": "https://merchant.example/products/pendant",
  "mintall:issuedFor": { "domain": "merchant.example", "productID": "..." },
  "mintall:status": { "canonicalSource": "..." }
}
```

Assets follow their parent product. If it is not active, the asset certificate
omits `mintall:contentCredentials`, `mintall:nft`, `verification`, and `proof`.
An asset Mintall does not know, or one with no certificate, returns 404.

## The proof block

`proof.jwt` is an RS256 JWT signed by Mintall. It expires 7 days after
issuance, so refetch the certificate rather than caching the token past its
`exp`.

| Claim    | Meaning                                      |
| -------- | -------------------------------------------- |
| `iss`    | The issuing API base URL                     |
| `iat`    | Issued at                                    |
| `exp`    | Expires, 7 days after `iat`                  |
| `domain` | The domain the certificate is authorized for |

The header carries a `kid`. Match it against the keys from
[JWKS](/api/verifying#verify-offline-with-jwks) to pick the right public key.