> For the complete documentation index, see [llms.txt](/llms.txt)

# Webhooks

When your OpenAPI document declares a top-level `webhooks` block, every generated SDK ships
standalone, tree-shakable **webhook verification helpers** — no client instance required. A spec
that declares no webhooks gets none of this surface, so an API with no event delivery does not
carry verifier code it can never use. They take the raw request body, the signature header, and your
signing secret, verify the signature in constant time, and return the parsed payload (or
throw on a bad or missing signature). Use them in your webhook handler before trusting a
delivery.

**TypeScript** (regenerated + byte-diffed in CI `a0f8af4b462c`)

```ts
import { verifyHmacWebhook } from 'glotto-sdk';

const event = await verifyHmacWebhook('<raw-body>', '<signature>', '<secret>');
console.log(event);
```

**React Native** (regenerated + byte-diffed in CI `a1fefe7d3458`)

```ts
import { verifyHmacWebhook } from 'glotto-sdk';

const event = await verifyHmacWebhook('<raw-body>', '<signature>', '<secret>');
console.log(event);
```

**Python** (regenerated + byte-diffed in CI `2242160f8958`)

```python
from glotto_sdk import verify_webhook

if not verify_webhook("<raw-body>", "<signature>", "<secret>"):
    raise ValueError("invalid webhook signature")
```

**Go** (regenerated + byte-diffed in CI `f0c565cc46f8`)

```go
package main

import (
    sdk "example.com/glotto-sdk-go"
)

func main() {
    if !sdk.VerifyWebhook("<raw-body>", "<signature>", "<secret>") {
        panic("invalid webhook signature")
    }
}
```

**Java** (regenerated + byte-diffed in CI `12c05e098737`)

```java
import com.glotto.Client;

public class Snippet {
    public static void main(String[] args) {
        if (!Client.verifyWebhook("<raw-body>", "<signature>", "<secret>")) {
            throw new IllegalArgumentException("invalid webhook signature");
        }
    }
}
```

**Kotlin** (regenerated + byte-diffed in CI `0f5e53ae2522`)

```kotlin
import com.glotto.Client

fun main() {
    require(Client.verifyWebhook("<raw-body>", "<signature>", "<secret>")) {
        "invalid webhook signature"
    }
}
```

**C#** (regenerated + byte-diffed in CI `c5013ce0e88b`)

```csharp
using Glotto;

if (!Client.VerifyWebhook("<raw-body>", "<signature>", "<secret>"))
{
    throw new Exception("invalid webhook signature");
}
```

**PHP** (regenerated + byte-diffed in CI `1acd16081b46`)

```php
<?php
require 'vendor/autoload.php';

if (!Glotto\Client::verifyWebhook("<raw-body>", "<signature>", "<secret>")) {
    throw new RuntimeException("invalid webhook signature");
}
```

**Ruby** (regenerated + byte-diffed in CI `a2b854f6593f`)

```ruby
require 'glotto'

unless Glotto::Client.verify_webhook("<raw-body>", "<signature>", "<secret>")
  raise "invalid webhook signature"
end
```

**Rust** (regenerated + byte-diffed in CI `716e9ec181d1`)

```rust
if verify_hmac_webhook(b"<raw-body>", "<signature>", "<secret>", WebhookEncoding::Hex).is_err() {
    panic!("invalid webhook signature");
}
```

**Swift** (regenerated + byte-diffed in CI `0cc357352baf`)

```swift
import Foundation
import GlottoSdk

do {
    _ = try verifyHmacWebhook(
        payload: Data("<raw-body>".utf8),
        signature: "<signature>",
        secret: "<secret>"
    )
} catch {
    print("Invalid webhook signature: \(error)")
}
```

**Dart** (regenerated + byte-diffed in CI `67567d6df435`)

```dart
import 'package:glotto_sdk/glotto_sdk.dart';

try {
  verifyHmacWebhook('<raw-body>'.codeUnits, '<signature>', '<secret>');
} on WebhookException catch (error) {
  print(error);
}
```

**Elixir** (regenerated + byte-diffed in CI `b97af402f1d7`)

```elixir
case Glotto.Webhook.verify_hmac("<raw-body>", "<signature>", "<secret>") do
  {:ok, payload} -> IO.inspect(payload)
  {:error, :invalid_signature} -> raise "invalid webhook signature"
end
```

## HMAC signatures

`verifyHmacWebhook` (TypeScript) / `verify_webhook` (Python) / `VerifyWebhook` (Go) compute an
HMAC-SHA256 of the raw payload with your secret and compare it to the provided signature using a
timing-safe equality check. The signature encoding (`hex` or `base64`) is selectable. A mismatch
raises `WebhookVerificationError`; a success returns the parsed body.

## Standard Webhooks

For providers that follow the [Standard Webhooks](https://www.standardwebhooks.com/) spec, the
SDK also emits `verifyStandardWebhook` — it reads the `webhook-id`, `webhook-timestamp`, and
`webhook-signature` headers, enforces a configurable timestamp tolerance (replay protection), and
verifies the base64 signature. Stripe-style signatures are handled by a sibling helper where the
spec advertises them.

## Why a standalone helper

Verification is **crypto over raw bytes**, so it can't go through the typed client — it runs in
your HTTP handler before any parsing. The helpers depend only on Web Crypto (no Node built-ins),
so the same function works in a server, an edge runtime, or a serverless handler.
