Quick start
-
Create an endpoint (UI or API) with an
https://URL and at least one event subscription. - Store the signing secret shown at creation time — it is never shown again.
-
On each delivery, verify the
x-credo-signatureheader before processing the payload.
Request headers
Every delivery includes:
| Header | Value |
|---|---|
Content-Type |
application/json |
X-Credo-Signature |
sha256=<hex_digest> |
X-Credo-Event |
The event type, e.g. document.sealed |
User-Agent |
EngineeringID-Webhooks/1.0 |
Verifying signatures
The signature is an HMAC-SHA256 hex digest of the raw request body, keyed with your endpoint's signing secret.
signature = HMAC-SHA256(secret, raw_body)
expected = "sha256=" + hex(signature)
Elixir / Phoenix
def valid_signature?(raw_body, secret, header) do
expected =
"sha256=" <>
(:crypto.mac(:hmac, :sha256, secret, raw_body)
|> Base.encode16(case: :lower))
Plug.Crypto.secure_compare(expected, header)
end
Python
import hmac, hashlib
def valid_signature(raw_body: bytes, secret: bytes, header: str) -> bool:
digest = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(f"sha256={digest}", header)
Node.js / TypeScript
import { createHmac, timingSafeEqual } from "crypto";
function validSignature(rawBody: Buffer, secret: Buffer, header: string): boolean {
const digest = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
return timingSafeEqual(Buffer.from(digest), Buffer.from(header));
}
Delivery behavior
2xx
as quickly as possible. If your handler does heavy work, acknowledge receipt immediately and process asynchronously.
Events
Every event payload has the same envelope: an event
type identifier, the organization_id
that owns it, an ISO 8601 timestamp, and an event-specific
data
object.
Document events
Document lifecycle changes — uploads, seals, deletions.
A document is uploaded or created in your organization.
{
"event": "document.created",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"id": "01HXYZ-doc-uuid",
"filename": "structural-report.pdf",
"content_type": "application/pdf",
"size": 2048576,
"created_by": {
"id": "01HXYZ-user-uuid",
"email": "[email protected]"
}
}
}
A document is sealed with a professional credential, creating an immutable, verifiable version.
{
"event": "document.sealed",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"id": "01HXYZ-doc-uuid",
"filename": "structural-report.pdf",
"version": 2,
"seal": {
"id": "01HXYZ-seal-uuid",
"verification_code": "CREDO-ABC123",
"sealed_by": {
"id": "01HXYZ-user-uuid",
"email": "[email protected]"
},
"credential": {
"license_number": "PE-12345",
"state_code": "CA",
"profession": "engineer"
}
}
}
}
A document is deleted from your organization.
{
"event": "document.deleted",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"id": "01HXYZ-doc-uuid",
"filename": "structural-report.pdf",
"deleted_by": {
"id": "01HXYZ-user-uuid",
"email": "[email protected]"
}
}
}
Credential events
Professional license additions and verifications.
A professional credential is added to the organization.
{
"event": "credential.created",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"id": "01HXYZ-cred-uuid",
"license_number": "PE-12345",
"state_code": "CA",
"profession": "engineer",
"status": "pending",
"created_by": {
"id": "01HXYZ-user-uuid",
"email": "[email protected]"
}
}
}
A credential passes board verification, confirming the license is valid and active.
{
"event": "credential.verified",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"id": "01HXYZ-cred-uuid",
"license_number": "PE-12345",
"state_code": "CA",
"profession": "engineer",
"status": "verified",
"verification_method": "board_lookup",
"verified_at": "2026-04-03T12:00:00Z"
}
}
Seal events
Cryptographic seals being created or revoked.
A seal record is written. A seal is the cryptographic proof linking a credential to a specific document version.
{
"event": "seal.created",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"id": "01HXYZ-seal-uuid",
"verification_code": "CREDO-ABC123",
"document_id": "01HXYZ-doc-uuid",
"credential_id": "01HXYZ-cred-uuid",
"document_hash": "sha256:a1b2c3d4...",
"sealed_by": {
"id": "01HXYZ-user-uuid",
"email": "[email protected]"
}
}
}
A seal is revoked, invalidating the sealed document version.
{
"event": "seal.revoked",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"id": "01HXYZ-seal-uuid",
"verification_code": "CREDO-ABC123",
"document_id": "01HXYZ-doc-uuid",
"reason": "Credential expired",
"revoked_by": {
"id": "01HXYZ-user-uuid",
"email": "[email protected]"
}
}
}
Member events
Organization membership changes.
A user joins the organization.
{
"event": "member.added",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"user": {
"id": "01HXYZ-user-uuid",
"email": "[email protected]"
},
"role": "member",
"added_by": {
"id": "01HXYZ-admin-uuid",
"email": "[email protected]"
}
}
}
A user is removed from the organization.
{
"event": "member.removed",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"user": {
"id": "01HXYZ-user-uuid",
"email": "[email protected]"
},
"removed_by": {
"id": "01HXYZ-admin-uuid",
"email": "[email protected]"
}
}
}
Batch events
Batch sealing operations.
A batch seal job finishes processing all documents. Includes success / failure counts.
{
"event": "batch.completed",
"organization_id": "01HXYZ-org-uuid",
"timestamp": "2026-04-03T12:00:00Z",
"data": {
"batch_id": "01HXYZ-batch-uuid",
"total": 25,
"succeeded": 23,
"failed": 2,
"initiated_by": {
"id": "01HXYZ-user-uuid",
"email": "[email protected]"
}
}
}
Need help integrating?
Webhook integrations are available on Enterprise accounts. Tell us about your use case and we'll help you wire it up.
Contact us
Get in touch
Tell us what you're building. We answer integration, schema, auth, rate-limit, SDK, and pricing questions — usually within a business day.
No spam, unsubscribe anytime. We respect your privacy.