> For the complete documentation index, see [llms.txt](https://docs.alignlabs.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.alignlabs.dev/align-api/webhooks.md).

# Webhooks

## Authentication

#### How to make sure the webhook request is originated from Align:

* Make sure `x-hmac-signature` is present in the header
* Generate the keyed hash of the payload using HMAC-SHA256 function and the API auth key
* Hex encode the hash
* Compare the hex encoded hash with the `x-hmac-signature` header sent by Align

## Events

We publish webhooks events for Customer, Onramp Transfer, Offramp Transfer, Cross Chain Transfer related activities. Here is event Payload structure:

```typescript
type WebhookEventPayload = {
    event_type: 
        'customer.kycs.updated' |
        'onramp_transfer.status.updated' |
        'cross_chain_transfer.status.updated' |
        'offramp_transfer.status.updated' |
        'virtual_account.created';
    entity_id: string;
    entity_type: 
        'customer' |
        'onramp_transfer' |
        'cross_chain_transfer' |
        'offramp_transfer' |
        'virtual_account';
    created_at: string;
}
```

## Customer Event

#### Customer KYC Updated Event

When a customer's KYC status is updated, a webhook event is triggered. The structure of this event provides details about the customer's entity and the time of the update. Below is an example structure of a `customer.kycs.updated` event:

```typescript
type CustomerKYCUpdatedWebhookEventPayload = {
  event_type: 'customer.kycs.updated';
  entity_id: string;
  entity_type: 'customer';
  created_at: string;
  event_payload?: {
    customer_id: string;
  };
  entity_object: {
    customer_id: string;
    email: string;
    company_name: string | null;
    first_name: string;
    last_name: string;
    type: 'individual' | 'corporate';
    kycs: {
      status: 'pending' | 'approved' | 'rejected';
      status_breakdown: {
        currency: 'aed' | 'eur' | 'usd';
        payment_rails: 'uaefts' | 'sepa' | 'ach' | 'wire' | 'swift';
        status: 'pending' | 'approved';
      }[];
      sub_status:
        | 'kyc_form_submission_started'
        | 'kyc_form_submission_accepted'
        | 'kyc_form_resubmission_required'
        | null;
      kyc_flow_link: string | null;
    } | null;
  };
};

```

This event helps track changes in a customer's KYC verification status.

## Onramp Transfer Event

In the event of a Onramp Transfer initiated via a **virtual account deposit**, the webhook event structure can include additional details about the virtual account. This is provided within the `event_payload` field under the `virtual_account` object.&#x20;

Event structure:

```typescript
type OnrampTransferWebhookEventPayload = {
    event_type: 'onramp_transfer.status.updated';
    entity_id: string;
    entity_type: 'onramp_transfer';
    event_payload?: {
        customer_id: string;
        virtual_account?: {
            id: string
        }
    }
    created_at: string;
}
```

## Offramp Transfer Event

Event structure:

```typescript
type OfframpTransferWebhookEventPayload = {
    event_type: 'offramp_transfer.status.updated';
    entity_id: string;
    entity_type: 'offramp_transfer';
    event_payload?: {
        customer_id: string;
    }
    created_at: string;
}
```

## Cross Chain Transfer Event

In the event of a Cross Chain Transfer initiated via a permanent route address deposit, the webhook event structure can include additional details about the permanent route address. This is provided within the `event_payload` field under the `permanent_route_address` object.&#x20;

Event structure:

```typescript
type CrossChainTransferWebhookEventPayload = {
    event_type: 'cross_chain_transfer.status.updated';
    entity_id: string;
    entity_type: 'cross_chain_transfer';
    event_payload?: {
        permanent_route_address?: {
            id: string
        }
    }
    created_at: string;
}
```

## Virtual Account Event

Event structure for Virtual Account Transfer:

```typescript
type VirtualAccountWebhookEventPayload = {
    event_type: 'virtual_account.created';
    entity_id: string;
    entity_type: 'virtual_account';
    created_at: string;
}
```
