Trusteddit Enrollment API
Base URL: https://enroll.trusteddit.com
Authentication
All API requests must include a valid Amazon Cognito ID token in the Authorization header. Tokens are issued by your app's Cognito User Pool and expire after 1 hour.
Authorization: Bearer <cognito-id-token>
Content-Type: application/jsonThe Trusteddit enrollment API validates the JWT signature against your Cognito User Pool public keys. Ensure your COGNITO_USER_POOL_ID and COGNITO_CLIENT_ID are registered with Trusteddit during platform onboarding.
Rate Limits
| Limit | Value | Scope | Notes |
|---|---|---|---|
| Enrollments per day | 10 | Per authenticated user | Resets at 00:00 UTC |
| Requests per minute | 60 | Per platform API key | Applies across all endpoints |
| Health check | Unlimited | Per IP | No auth required |
When a rate limit is exceeded, the API responds with HTTP 429 and a Retry-After header indicating the number of seconds to wait before retrying.
/api/v1/enroll
Submit a PKCS#10 Certificate Signing Request (CSR) to obtain a device certificate from the Trusteddit CA. The CSR must use ECDSA P-256 and include an opaque signer ID as the certificate Common Name.
Request Body
// Content-Type: application/json
{
"csr": "-----BEGIN CERTIFICATE REQUEST-----\n..."
// PEM-encoded PKCS#10 CSR
// Subject CN must be in format: ph_<hex16>@thephenom.app
// Key algorithm: EC / P-256 (ECDSA)
// Signature algorithm: ES256 (ECDSA with SHA-256)
}Response — 201 Created
{
"certificate": "-----BEGIN CERTIFICATE-----\n...",
// PEM-encoded device certificate
// CN: ph_<hex16>@thephenom.app
// Issuer: Trusteddit-Journalist-Issuer-CA
// Algorithm: ES256 (ECDSA P-256)
// Validity: 90 days from issuance
"chain": [
"-----BEGIN CERTIFICATE-----\n...", // Trusteddit-Journalist-Issuer-CA
"-----BEGIN CERTIFICATE-----\n..." // Trusteddit Intermediate CA
],
// Full CA chain, ordered from issuing CA to intermediate.
// Append to certificate when constructing the C2PA manifest.
"expiresAt": "2026-07-01T00:00:00Z",
// ISO 8601 UTC expiry of the device certificate.
// Schedule re-enrollment before this date.
"signerId": "[email protected]",
// Echo of the signer ID extracted from the CSR CN.
// Confirm this matches what you submitted.
"serialNumber": "3a:9f:c2:1d:..."
// Hex-encoded certificate serial number.
// Store this to correlate with revocation records if needed.
}Response — 4xx / 5xx Errors
{
"code": "INVALID_CSR_FORMAT",
// Machine-readable error code — see Error Codes table below
"message": "CSR signature verification failed",
// Human-readable explanation
"requestId": "req_01hvmk..."
// Opaque request ID — include in support emails
}/api/v1/health
Returns the operational status of the enrollment API and its upstream CA dependency. No authentication required. Suitable for uptime monitoring and pre-flight checks in your app.
// 200 OK — all systems operational
{
"status": "ok",
"ca": "reachable",
"version": "1.0.3",
"timestamp": "2026-04-03T12:00:00Z"
}
// 503 Service Unavailable — CA unreachable or degraded
{
"status": "degraded",
"ca": "unreachable",
"message": "CA signing endpoint is not responding",
"timestamp": "2026-04-03T12:00:00Z"
}Error Codes
| Code | HTTP | Description | Resolution |
|---|---|---|---|
| AUTH_FAILED | 401 | The Authorization header is missing, malformed, or the JWT is expired / invalid. | Re-authenticate the user via Cognito and retry with a fresh ID token. |
| MISSING_CSR | 400 | The request body does not contain a "csr" field, or the field is empty. | Ensure the JSON body includes a PEM-encoded CSR in the "csr" key. |
| INVALID_CSR_FORMAT | 422 | The CSR could not be parsed, the signature is invalid, or the algorithm is not ES256/P-256. | Regenerate the CSR using @peculiar/x509 with ECDSA P-256. Verify the CSR is PEM-encoded (begins with "-----BEGIN CERTIFICATE REQUEST-----"). |
| RATE_LIMITED | 429 | The authenticated user has exceeded 10 enrollment requests within a 24-hour window. | Wait until the rate limit window resets (see Retry-After header) before retrying. |
| CA_ERROR | 502 | The Trusteddit CA encountered an internal error while signing the certificate. | Retry with exponential backoff. If the error persists, contact [email protected]. |
Certificate Details
| Property | Value |
|---|---|
| Algorithm | ES256 (ECDSA with SHA-256) |
| Key Type | EC / P-256 (secp256r1 / prime256v1) |
| Validity Period | 90 days from time of issuance |
| Subject CN Format | ph_<hex16>@thephenom.app |
| Issuer CN | Trusteddit-Journalist-Issuer-CA |
| Key Usage | Digital Signature |
| Extended Key Usage | id-kp-contentCommitment (C2PA) |
| Basic Constraints | CA:FALSE |
| OCSP Responder | https://ocsp.trusteddit.com |
| CRL Distribution Point | https://crl.trusteddit.com/issuer.crl |
Trust Chain
Trusteddit issues device certificates from the Journalist Issuer CA, which chains through the Trusteddit Intermediate CA to a root CA recognised by the C2PA Trust List. Verifying applications resolve this chain automatically when checking C2PA manifests.
Root CA operated by Trusteddit, anchoring the trust chain
Trusteddit-operated intermediate CA (ES256, 3-year validity)
Issuing CA for per-install device certificates (ES256, 1-year validity)
Per-install certificate issued to your app (ES256, 90-day validity)
The complete trust chain (device certificate + issuer CA + intermediate CA) is included in the chain field of the enrollment response. Embed this chain in your C2PA manifest's signature info so verifying applications can build the full path to the trust anchor without additional HTTP lookups.