Event Types
See below for a list of all webhook event categories and associated payloads.
Event Categories
Account Balance Activity
| Category | Payload Type | Description | Trigger |
|---|---|---|---|
MURAL_ACCOUNT_BALANCE_ACTIVITY | account_credited | Funds received in a Mural account | Incoming blockchain transaction confirmed |
MURAL_ACCOUNT_BALANCE_ACTIVITY | account_debited | Funds sent from a Mural account | Outgoing blockchain transaction confirmed |
Account Credited
interface AccountCreditedPayload {
type: 'account_credited';
accountId: string;
organizationId: string;
transactionId: string; // this is the id that will appear in the Transactions API
accountWalletAddress: string;
tokenAmount: {
blockchain: string;
tokenAmount: number;
tokenSymbol: string;
tokenContractAddress: string;
};
transactionDetails: {
blockchain: string;
transactionDate: string; // ISO 8601 datetime
transactionHash: string;
sourceWalletAddress: string;
destinationWalletAddress: string;
};
}Account Debited
interface AccountDebitedPayload {
type: 'account_debited';
accountId: string;
organizationId: string;
transactionId: string; // this is the id that will appear in the Transactions API
accountWalletAddress: string;
tokenAmount: {
blockchain: string;
tokenAmount: number;
tokenSymbol: string;
tokenContractAddress: string;
};
transactionDetails: {
blockchain: string;
transactionDate: string; // ISO 8601 datetime
transactionHash: string;
sourceWalletAddress: string;
destinationWalletAddress: string;
};
}Payout Request
| Category | Payload Type | Description | Trigger |
|---|---|---|---|
PAYOUT_REQUEST | payout_request_status_changed | Payout request status has changed | Payout request transitions to a new status |
PAYOUT_REQUEST | payout_status_changed | Individual payout status has changed | Fiat or blockchain payout transitions to a new status |
Payout Request Status Changed Payload
This event is triggered when the overall payout request status changes. A payout request may contain multiple individual payouts (recipients).
interface PayoutRequestStatusChangedPayload {
type: 'payout_request_status_changed';
organizationId: string;
payoutRequestId: string;
statusChangeDetails: {
previousStatus: PayoutRequestStatus;
currentStatus: PayoutRequestStatus;
};
}
type PayoutRequestStatus =
| { type: 'awaitingExecution' } // Payout request created, awaiting blockchain execution
| { type: 'pending' } // Blockchain transaction submitted, payouts in progress
| { type: 'executed' } // All payouts completed successfully
| { type: 'failed' } // One or more payouts failed
| { type: 'canceled' }; // Payout request was canceledExample Payload
{
"type": "payout_request_status_changed",
"organizationId": "e77ee023-fa9a-4d42-9be9-74f3a2bb2042",
"payoutRequestId": "a3d9f1b2-7c4e-4a6f-9b1d-2e8c5f7a9d30",
"statusChangeDetails": {
"previousStatus": { "type": "awaitingExecution" },
"currentStatus": { "type": "pending" }
}
}Payout Status Changed Payload
This event is triggered when an individual payout's status changes. The statusChangeDetails object contains payout type and status information, where type indicates whether this is a fiat (bank transfer) or blockchain payout.
interface PayoutStatusChangedPayload {
type: 'payout_status_changed';
organizationId: string;
payoutRequestId: string;
payoutId: string;
statusChangeDetails: FiatPayoutStatusChangeDetails | BlockchainPayoutStatusChangeDetails;
}
// Fiat payout status change details (bank transfers)
interface FiatPayoutStatusChangeDetails {
type: 'fiat';
previousStatus: FiatPayoutStatus;
currentStatus: FiatPayoutStatus;
}
// Blockchain payout status change details
interface BlockchainPayoutStatusChangeDetails {
type: 'blockchain';
previousStatus: BlockchainPayoutStatus;
currentStatus: BlockchainPayoutStatus;
}
// Fiat payout statuses - objects with type field
type FiatPayoutStatus =
| { type: 'created' } // Payout created, awaiting processing
| { type: 'pending' } // Payout submitted to provider
| { type: 'onHold' } // Payout on hold (compliance review)
| { type: 'completed' } // Funds delivered successfully
| { type: 'failed' } // Payout failed
| { type: 'canceled' } // Payout was canceled
| { type: 'refundInProgress' } // Refund is being processed
| { type: 'refunded' }; // Funds refunded to source account
// Blockchain payout statuses - objects with type field
type BlockchainPayoutStatus =
| { type: 'awaitingExecution' } // Awaiting blockchain transaction
| { type: 'pending' } // Transaction submitted to blockchain
| { type: 'executed' } // Transaction confirmed on blockchain
| { type: 'failed' } // Transaction failed
| { type: 'canceled' }; // Payout was canceledExample Fiat Payout Payload
{
"type": "payout_status_changed",
"organizationId": "e77ee023-fa9a-4d42-9be9-74f3a2bb2042",
"payoutRequestId": "a3d9f1b2-7c4e-4a6f-9b1d-2e8c5f7a9d30",
"payoutId": "b4e8c2d1-5f6a-4b7c-8d9e-1a2b3c4d5e6f",
"statusChangeDetails": {
"type": "fiat",
"previousStatus": { "type": "created" },
"currentStatus": { "type": "pending" }
}
}Example Blockchain Payout Payload
{
"type": "payout_status_changed",
"organizationId": "e77ee023-fa9a-4d42-9be9-74f3a2bb2042",
"payoutRequestId": "a3d9f1b2-7c4e-4a6f-9b1d-2e8c5f7a9d30",
"payoutId": "c5f9d3e2-6a7b-4c8d-9e1f-2b3c4d5e6f7a",
"statusChangeDetails": {
"type": "blockchain",
"previousStatus": { "type": "pending" },
"currentStatus": { "type": "executed" }
}
}Payin
| Category | Payload Type | Description | Trigger |
|---|---|---|---|
PAYIN | payin_status_changed | Payin status has changed | Payin is created, or transitions to a new status |
Payin Status Changed Payload
This event is triggered when a payin is created and whenever its status subsequently changes. The previousStatus field is null only on the initial creation event; for all subsequent transitions, it holds the prior status.
interface PayinStatusChangedPayload {
type: 'payin_status_changed';
organizationId: string;
payinId: string;
statusChangeDetails: {
previousStatus: PayinStatus | null; // null on initial creation
currentStatus: PayinStatus;
};
}
type PayinStatus =
| { type: 'created' }
| { type: 'pending' }
| { type: 'on-hold' }
| { type: 'completed' }
| { type: 'failed' }
| { type: 'canceled' }
| { type: 'refunded' };Fetch full payin detail (including timestamps and the reason on failure) from the get Payin endpoint.
Example Creation Payload
{
"type": "payin_status_changed",
"organizationId": "e77ee023-fa9a-4d42-9be9-74f3a2bb2042",
"payinId": "d192b782-647c-4011-8184-ab9c1e1b5b3d",
"statusChangeDetails": {
"previousStatus": null,
"currentStatus": { "type": "created" }
}
}Example Transition Payload
{
"type": "payin_status_changed",
"organizationId": "e77ee023-fa9a-4d42-9be9-74f3a2bb2042",
"payinId": "d192b782-647c-4011-8184-ab9c1e1b5b3d",
"statusChangeDetails": {
"previousStatus": { "type": "pending" },
"currentStatus": { "type": "completed" }
}
}Business Verification
| Category | Payload Type | Description | Trigger |
|---|---|---|---|
BUSINESS_VERIFICATION_STATUS | business_verification_status_changed | Business verification status has been updated | KYC/KYB review completed or status change occurred |
Verification Status Changed Payload
interface BusinessVerificationStatusChangedPayload {
type: 'business_verification_status_changed';
organizationId: string;
previousStatus: MuralKycVerificationStatus;
currentStatus: MuralKycVerificationStatus;
verificationId: string;
updatedAt: string; // ISO 8601 datetime
}
// Status objects returned based on verification state
type MuralKycVerificationStatus =
| { type: 'inactive' }
| { type: 'pending' }
| { type: 'approved'; approvedAt: string }
| { type: 'errored'; details: string; erroredAt: string }
| { type: 'rejected'; reason: string; rejectedAt: string };Example Status Objects
Inactive Status:
{ "type": "inactive" }Pending Status:
{ "type": "pending" }Approved Status:
{
"type": "approved",
"approvedAt": "2024-03-21T10:30:00Z"
}Errored Status:
{
"type": "errored",
"details": "Verification encountered an error",
"erroredAt": "2024-03-21T10:30:00Z"
}Rejected Status:
{
"type": "rejected",
"reason": "Verification was rejected",
"rejectedAt": "2024-03-21T10:30:00Z"
}Organization Terms of Service
| Category | Payload Type | Description | Trigger |
|---|---|---|---|
ORGANIZATION_TOS | tos_accepted | Organization accepted Terms of Service | Initial TOS acceptance by organization |
TOS Accepted Payload
interface OrganizationTosAcceptedPayload {
type: 'tos_accepted';
organizationId: string;
signedAt: string; // ISO 8601 datetime
source: 'ui' | 'api' | 'test';
}Source Field Values
ui: TOS was accepted through the Mural web application by an authenticated userapi: TOS was accepted via the public REST API endpointtest: TOS event was triggered as a test webhook
Example Payload
{
"type": "tos_accepted",
"organizationId": "e77ee023-fa9a-4d42-9be9-74f3a2bb2042",
"signedAt": "2024-03-21T10:30:00Z",
"source": "ui"
}Note: This event is only sent on initial TOS acceptance. Re-signing or updating agreements will not trigger additional webhook events.
Compliance Review
| Category | Payload Type | Description | Trigger |
|---|---|---|---|
COMPLIANCE_REVIEW | compliance_review_status_changed | Compliance review status has changed | Compliance review transitions to a new status |
COMPLIANCE_REVIEW | attestation_validation_status_changed | Attestation validation status has changed | An attestation's asynchronous validation finishes |
Compliance Review Status Changed Payload
This event is triggered whenever a compliance review (individual or business) transitions to a new status — for example when a draft is submitted, when a submitted review moves into review, or when a review reaches a terminal approved, rejected, or error state.
The organizationId identifies the organization that owns the compliance review; for organizations with a parent/child structure this may be a parent or child organization. Both previousStatus and currentStatus use the same shape as the review status returned by the get Compliance Review endpoint.
interface ComplianceReviewStatusChangedPayload {
type: 'compliance_review_status_changed';
organizationId: string;
complianceReviewId: string;
previousStatus: ComplianceReviewStatus;
currentStatus: ComplianceReviewStatus;
updatedAt: string; // ISO 8601 datetime
}
// Each status has a type; some statuses carry extra fields
type ComplianceReviewStatus =
| { type: 'draft' } // Review created, awaiting attestation uploads
| { type: 'submitted'; submittedAt: string } // Submitted; submission validations will begin shortly
| { type: 'validatingSubmission' } // Submission validations are currently running
| { type: 'submissionValidationsFailed' } // One or more submission validations failed
| { type: 'inReview'; submittedAt: string } // Currently being evaluated
| { type: 'additionalInformationRequested'; rfiId: string } // More information required; rfiId identifies the outstanding RFI
| { type: 'approved'; submittedAt: string; approvedAt: string } // Approved; requested KYC tier granted
| {
type: 'rejected';
submittedAt: string;
rejectedAt: string;
rejectionDescription: string; // Reason the review was rejected
}
| {
type: 'error';
submittedAt: string;
errorDescription: string; // Description of the processing error
};Status Field Notes
submittedAtis present onsubmitted,inReview,approved,rejected, anderror. It is absent ondraft,validatingSubmission, andsubmissionValidationsFailed.approvedAt/rejectedAtare populated only once the review reaches the corresponding terminal state.rejectionDescriptionis populated only on therejectedstatus.errorDescriptionis populated only on theerrorstatus.rfiIdis populated only on theadditionalInformationRequestedstatus. It identifies the RFI to answer; see RFI.
Fetch full compliance review detail (tier, type, attestations, and additional metadata) from the get Compliance Review endpoint.
Example Submission Payload
{
"type": "compliance_review_status_changed",
"organizationId": "org_abc123",
"complianceReviewId": "review_xyz789",
"previousStatus": { "type": "draft" },
"currentStatus": {
"type": "submitted",
"submittedAt": "2026-02-24T12:00:00.000Z"
},
"updatedAt": "2026-02-24T12:00:00.000Z"
}Example Approval Payload
{
"type": "compliance_review_status_changed",
"organizationId": "org_abc123",
"complianceReviewId": "review_xyz789",
"previousStatus": {
"type": "inReview",
"submittedAt": "2026-02-24T12:00:00.000Z"
},
"currentStatus": {
"type": "approved",
"submittedAt": "2026-02-24T12:00:00.000Z",
"approvedAt": "2026-02-25T10:30:00.000Z"
},
"updatedAt": "2026-02-25T10:30:00.000Z"
}Example Rejection Payload
{
"type": "compliance_review_status_changed",
"organizationId": "org_abc123",
"complianceReviewId": "review_def456",
"previousStatus": {
"type": "inReview",
"submittedAt": "2026-02-24T12:00:00.000Z"
},
"currentStatus": {
"type": "rejected",
"submittedAt": "2026-02-24T12:00:00.000Z",
"rejectedAt": "2026-02-25T10:30:00.000Z",
"rejectionDescription": "Provided information does not meet KYC requirements."
},
"updatedAt": "2026-02-25T10:30:00.000Z"
}Example Error Payload
{
"type": "compliance_review_status_changed",
"organizationId": "org_abc123",
"complianceReviewId": "review_def456",
"previousStatus": {
"type": "inReview",
"submittedAt": "2026-02-24T12:00:00.000Z"
},
"currentStatus": {
"type": "error",
"submittedAt": "2026-02-24T12:00:00.000Z",
"errorDescription": "Verification provider returned an unexpected error."
},
"updatedAt": "2026-02-25T10:30:00.000Z"
}Attestation Validation Status Changed Payload
Some attestations submitted to a compliance review, such as identity documents and addresses, are validated asynchronously. This event tells you the moment a specific attestation finishes, so you do not have to poll the review while validations run. It is delivered to webhooks subscribed to the COMPLIANCE_REVIEW category. It is not sent for associated-person attestations; poll the associated person for their validationStatus.
interface AttestationValidationStatusChangedPayload {
type: 'attestation_validation_status_changed';
organizationId: string;
complianceReviewId: string;
attestationId: string;
attestationType: AttestationType; // e.g. 'individualIdentityDocument'
statusChangeDetails: {
previousStatus: { type: 'pending' };
currentStatus: AttestationResolvedValidationStatus;
};
updatedAt: string; // ISO 8601 datetime
}
type AttestationResolvedValidationStatus =
| { type: 'approved' } // The attestation passed every validation
| { type: 'failed'; failures: AttestationValidationFailure[] };currentStatus carries the same approved and failed shapes the attestation has in the get Compliance Review endpoint response, so a failed status arrives with its failures already populated — ordered most-actionable first. previousStatus is always pending: an attestation leaves pending once and never returns to it.
An attestation that fails validation does not by itself fail the review. Correct the attestation and resubmit it; each resubmission that resolves emits another event.
Example Approval Payload
{
"type": "attestation_validation_status_changed",
"organizationId": "org_abc123",
"complianceReviewId": "review_xyz789",
"attestationId": "attestation_def456",
"attestationType": "individualIdentityDocument",
"statusChangeDetails": {
"previousStatus": { "type": "pending" },
"currentStatus": { "type": "approved" }
},
"updatedAt": "2024-03-21T10:30:00.000Z"
}Example Failure Payload
{
"type": "attestation_validation_status_changed",
"organizationId": "org_abc123",
"complianceReviewId": "review_xyz789",
"attestationId": "attestation_def456",
"attestationType": "individualIdentityDocument",
"statusChangeDetails": {
"previousStatus": { "type": "pending" },
"currentStatus": {
"type": "failed",
"failures": [
{
"severity": "WARNING",
"failureInfo": {
"type": "general",
"failureCode": "POOR_QUALITY"
}
}
]
}
},
"updatedAt": "2024-03-21T10:30:00.000Z"
}RFI
| Category | Payload Type | Description | Trigger |
|---|---|---|---|
RFI | rfi_created | A request for information was raised | A reviewer raises an RFI |
RFI | rfi_status_changed | RFI status has changed | The RFI transitions to a new status |
A reviewer raises a request for information (RFI) when they need more from you before a compliance review can continue. See Requests for Information (RFIs) for the lifecycle and Responding to RFIs Programmatically for a full walkthrough.
Both events carry an origin that names what the RFI was raised on. Read its type to know which id it carries. Every RFI is currently raised on a compliance review.
type RfiEventOrigin = {
type: 'complianceReview';
complianceReviewId: string;
};
type RfiStatusType =
| 'outstanding' // The reviewer is waiting for a response
| 'validatingSubmission' // Your submission is being validated
| 'submissionValidationsFailed' // One or more submission validations failed; correct and submit again
| 'submitted' // Your response was submitted; follow the compliance review for the outcome
| 'cancelled'; // The request was cancelled; read the RFI for the reasonRFI Created Payload
This event is triggered when a reviewer raises an RFI. The compliance review it was raised on moves to additionalInformationRequested at the same time, and you also receive a compliance_review_status_changed event. Read the RFI from the get RFI endpoint to see what is requested.
interface RfiCreatedPayload {
type: 'rfi_created';
organizationId: string;
rfiId: string;
origin: RfiEventOrigin;
createdAt: string; // ISO 8601 datetime the reviewer made the request
}Example Payload
{
"type": "rfi_created",
"organizationId": "0c1c0f50-7a89-4e3a-9b1a-1d4ce4d6f001",
"rfiId": "3f1a9c22-55b8-4e01-9a7d-2c4f6b8e1d03",
"origin": {
"type": "complianceReview",
"complianceReviewId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
"createdAt": "2026-02-25T09:15:00.000Z"
}RFI Status Changed Payload
This event is triggered whenever an RFI moves to a different status: for example, when your submission starts validating, fails validation, is submitted, or the request is cancelled. Each step is its own event, so a failed resubmission sends two: one into validatingSubmission, and one back to submissionValidationsFailed.
The payload carries only the status types. Read the RFI from the get RFI endpoint to see the detail behind a status, such as the failures of a rejected submission.
interface RfiStatusChangedPayload {
type: 'rfi_status_changed';
organizationId: string;
rfiId: string;
origin: RfiEventOrigin;
statusChangeDetails: {
previousStatus: RfiStatusType;
currentStatus: RfiStatusType;
};
updatedAt: string; // ISO 8601 datetime
}Example Payload
{
"type": "rfi_status_changed",
"organizationId": "0c1c0f50-7a89-4e3a-9b1a-1d4ce4d6f001",
"rfiId": "3f1a9c22-55b8-4e01-9a7d-2c4f6b8e1d03",
"origin": {
"type": "complianceReview",
"complianceReviewId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
"statusChangeDetails": {
"previousStatus": "validatingSubmission",
"currentStatus": "submitted"
},
"updatedAt": "2026-02-26T14:05:00.000Z"
}Updated 14 days ago

