{"openapi":"3.1.0","info":{"title":"Sunlit Daymarks API","version":"1.0.0","summary":"Create and verify cryptographic document timestamps (daymarks).","description":"The Daymarks API turns a document's SHA-256 hash into a signed, independently\nverifiable timestamp proof. You hash documents yourself and send **only the hash** —\nthe original content never leaves your systems.\n\n## Authentication\nAuthenticated endpoints accept an API key as either an\n`Authorization: Bearer <key>` header or an `X-API-Key: <key>` header.\nCreate and revoke keys from your account dashboard. Keys look like\n`dk_live_…` and are shown in full only once, at creation.\n\nVerification and authority-key endpoints are public and need no key.","contact":{"name":"Sunlit Bytes","url":"https://sunlitbytes.com"}},"servers":[{"url":"https://www.daymarks.app","description":"This deployment"}],"tags":[{"name":"Daymarks","description":"Create and retrieve timestamp proofs."},{"name":"Certificates","description":"Render printable PDF certificates."},{"name":"Verification","description":"Independently verify a proof. Public."},{"name":"Authorities","description":"Published signing keys. Public."},{"name":"Account","description":"Identify the calling key."},{"name":"API Keys","description":"Manage keys (browser session / dashboard)."}],"security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"paths":{"/api/v1/daymarks":{"post":{"tags":["Daymarks"],"summary":"Create a daymark","description":"Seal a document hash: sign a Merkle batch header with the authority's Ed25519 key, append it to the hash-chained log, anchor it to an external RFC 3161 authority (best-effort), and persist it to the calling key's account.","operationId":"createDaymark","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDaymarkRequest"}}}},"responses":{"201":{"description":"Daymark created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Daymark"}}}},"400":{"description":"Invalid docHash","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Daymarks"],"summary":"List daymarks","description":"Return the calling key owner's saved daymarks, newest first.","operationId":"listDaymarks","responses":{"200":{"description":"A list of daymarks","content":{"application/json":{"schema":{"type":"object","properties":{"daymarks":{"type":"array","items":{"$ref":"#/components/schemas/Daymark"}}},"required":["daymarks"]}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/daymarks/{id}":{"get":{"tags":["Daymarks"],"summary":"Get a daymark","operationId":"getDaymark","parameters":[{"name":"id","in":"path","required":true,"description":"Daymark identifier (UUID).","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The daymark","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Daymark"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/daymarks/verify":{"post":{"tags":["Verification"],"summary":"Verify a proof","description":"Re-check a proof's authority signature, Merkle inclusion, and RFC 3161 anchor. Supply `docHash` to confirm the proof still matches a specific document; omit it to verify the proof as-is. This endpoint is public.","operationId":"verifyDaymark","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyRequest"}}}},"responses":{"200":{"description":"Verification report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationReport"}}}},"400":{"description":"A valid proof is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/daymarks/certificate":{"post":{"tags":["Certificates"],"summary":"Generate a certificate (from a proof)","description":"Render a printable PDF certificate for a supplied proof. The proof must verify; the response is the PDF binary (`application/pdf`).","operationId":"createCertificate","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertificateRequest"}}}},"responses":{"200":{"description":"PDF certificate","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"A valid proof is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The proof failed verification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/daymarks/{id}/certificate":{"get":{"tags":["Certificates"],"summary":"Generate a certificate (by daymark id)","description":"Render a PDF certificate for one of the calling key's stored daymarks.","operationId":"getDaymarkCertificate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"PDF certificate","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The proof failed verification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/authorities":{"get":{"tags":["Authorities"],"summary":"List signing authorities","description":"The public keys used to verify daymark proofs. Public.","operationId":"listAuthorities","security":[],"responses":{"200":{"description":"Authorities","content":{"application/json":{"schema":{"type":"object","properties":{"authorities":{"type":"array","items":{"$ref":"#/components/schemas/Authority"}}},"required":["authorities"]}}}}}}},"/api/v1/me":{"get":{"tags":["Account"],"summary":"Identify the calling key","operationId":"getMe","responses":{"200":{"description":"The authenticated principal","content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string"},"keyId":{"type":"string"},"keyName":{"type":"string"}},"required":["userId","keyId","keyName"]}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/keys":{"get":{"tags":["API Keys"],"summary":"List API keys","description":"List the signed-in user's keys. Requires a browser session cookie.","operationId":"listApiKeys","security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Keys (secrets are never returned)","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}},"required":["keys"]}}}},"401":{"description":"Sign in required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["API Keys"],"summary":"Create an API key","description":"Mint a new key. The full secret is returned only in this response.","operationId":"createApiKey","security":[{"cookieAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}}},"responses":{"201":{"description":"The new key, including its one-time secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedApiKey"}}}},"401":{"description":"Sign in required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/keys/{id}":{"delete":{"tags":["API Keys"],"summary":"Revoke an API key","operationId":"revokeApiKey","security":[{"cookieAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Revoked","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean"}}}}}},"401":{"description":"Sign in required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"dk_live_…","description":"An API key sent as `Authorization: Bearer <key>`."},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key","description":"An API key sent as `X-API-Key: <key>`."},"cookieAuth":{"type":"apiKey","in":"cookie","name":"better-auth.session_token","description":"Browser session cookie set after sign-in. Used by the dashboard."}},"schemas":{"Error":{"type":"object","properties":{"statusCode":{"type":"integer","example":400},"statusMessage":{"type":"string","example":"docHash must be a 64-character SHA-256 hex digest"},"message":{"type":"string"}},"required":["statusCode","statusMessage"]},"CreateDaymarkRequest":{"type":"object","required":["docHash"],"properties":{"docHash":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Lowercase SHA-256 hex digest of your document.","example":"08f7c58ed07dc05c605cfaa281cd33b550eb3e5ace291dcd89f43768ad3d9a5d"},"label":{"type":"string","maxLength":200,"description":"A human-readable label for the daymark.","example":"Q2 Board Resolution"}}},"VerifyRequest":{"type":"object","required":["proof"],"properties":{"proof":{"$ref":"#/components/schemas/DocumentProof"},"docHash":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Optional. The document hash to check the proof against. Defaults to the proof's own hash."}}},"CertificateRequest":{"type":"object","required":["proof"],"properties":{"proof":{"$ref":"#/components/schemas/DocumentProof"},"label":{"type":"string","maxLength":200,"description":"Document title shown on the certificate."}}},"MerkleStep":{"type":"object","properties":{"side":{"type":"string","enum":["left","right"]},"hash":{"type":"string"}},"required":["side","hash"]},"BatchHeader":{"type":"object","properties":{"version":{"type":"string","example":"daymarks-batch-v1"},"tsa_id":{"type":"string"},"merkle_root":{"type":"string"},"batch_start_time":{"type":"string","format":"date-time"},"batch_end_time":{"type":"string","format":"date-time"},"log_index":{"type":"integer"},"hash_alg":{"type":"string","example":"sha256"},"previous_log_hash":{"type":["string","null"]}}},"TsaProof":{"type":"object","properties":{"tsa_id":{"type":"string"},"alg":{"type":"string","example":"Ed25519"},"batch_header":{"$ref":"#/components/schemas/BatchHeader"},"signature":{"type":"string","description":"Base64 Ed25519 signature over the canonical batch header."},"merkle_path":{"type":"array","items":{"$ref":"#/components/schemas/MerkleStep"}},"claimed_time":{"type":"string","format":"date-time"}}},"Anchor":{"type":"object","properties":{"type":{"type":"string","example":"rfc3161"},"status":{"type":"string","enum":["confirmed","unavailable"]},"tsa":{"type":"string","description":"Timestamp authority URL."},"token":{"type":"string","description":"Base64 RFC 3161 TimeStampToken (when confirmed)."},"gen_time":{"type":"string","format":"date-time"},"serial":{"type":"string"},"error":{"type":"string"}},"required":["type","status","tsa"]},"DocumentProof":{"type":"object","description":"A self-contained, independently verifiable daymark proof (daymarks-json-v2).","properties":{"encoding":{"type":"string","example":"daymarks-json-v2"},"hash_alg":{"type":"string","example":"sha256"},"doc_hash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"authority":{"type":"object","properties":{"id":{"type":"string"},"alg":{"type":"string","example":"Ed25519"},"public_key":{"type":"string","description":"Base64 SPKI public key."}}},"tsas":{"type":"array","items":{"$ref":"#/components/schemas/TsaProof"}},"anchors":{"type":"array","items":{"$ref":"#/components/schemas/Anchor"}}},"required":["encoding","hash_alg","doc_hash","authority","tsas","anchors"]},"Daymark":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"docHash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"logIndex":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"proof":{"$ref":"#/components/schemas/DocumentProof"}},"required":["id","label","docHash","logIndex","createdAt","proof"]},"VerificationReport":{"type":"object","properties":{"valid":{"type":"boolean"},"doc_hash_matches":{"type":"boolean"},"proven_before":{"type":["string","null"],"format":"date-time"},"authority":{"type":"array","items":{"type":"object","properties":{"tsa_id":{"type":"string"},"signature_valid":{"type":"boolean"},"merkle_valid":{"type":"boolean"},"time":{"type":"string","format":"date-time"}}}},"anchors":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"status":{"type":"string"},"valid":{"type":"boolean"},"time":{"type":"string","format":"date-time"},"reason":{"type":"string"}}}}},"required":["valid","doc_hash_matches","proven_before","authority","anchors"]},"Authority":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"alg":{"type":"string","example":"Ed25519"},"public_key":{"type":"string","description":"Base64 SPKI public key."}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string","description":"Non-secret display prefix, e.g. dk_live_AbC123."},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"revoked":{"type":"boolean"}}},"CreatedApiKey":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","properties":{"key":{"type":"string","description":"The full secret. Shown only once.","example":"dk_live_…"}},"required":["key"]}]},"CreateApiKeyRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":60,"example":"CI pipeline"}}}}}}