nahook

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2026 License: MIT Imports: 14 Imported by: 0

README

Nahook Go SDK

Official Go SDK for Nahook — the webhook delivery platform.

Installation

go get github.com/getnahook/nahook-go

Requires Go 1.21+.

Quick Start

Ingestion Client

Use the client package to send webhooks to your endpoints.

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    nahook "github.com/getnahook/nahook-go"
    "github.com/getnahook/nahook-go/client"
)

func main() {
    c, err := client.New("nhk_us_your_api_key",
        client.WithTimeout(10*time.Second),
        client.WithRetries(3),
    )
    if err != nil {
        log.Fatal(err)
    }

    // The SDK automatically routes requests to the correct regional API
    // based on your API key prefix (nhk_us_... → US, nhk_eu_... → EU,
    // nhk_ap_... → Asia Pacific). No configuration needed.
    //
    // To override for testing/local dev:
    //   c, err := client.New("nhk_us_...", client.WithBaseURL("http://localhost:3001"))
    //
    // For unit tests, mock the SDK client at the dependency injection boundary.
    // For integration tests, override the base URL to point at a local server.

    ctx := context.Background()

    // Send to a specific endpoint
    result, err := c.Send(ctx, "ep_abc123", nahook.SendOptions{
        Payload: map[string]interface{}{
            "event":   "order.created",
            "orderId": "ord_12345",
            "amount":  99.99,
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Delivery: %s (status: %s)\n", result.DeliveryID, result.Status)

    // Fan-out by event type
    triggerResult, err := c.Trigger(ctx, "order.paid", nahook.TriggerOptions{
        Payload: map[string]interface{}{
            "orderId": "ord_12345",
            "amount":  99.99,
        },
        Metadata: map[string]string{
            "region": "us-east-1",
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Triggered %d deliveries\n", len(triggerResult.DeliveryIDs))
}
Batch Operations
// Send to multiple endpoints at once (max 20)
batchResult, err := c.SendBatch(ctx, []nahook.SendBatchItem{
    {
        EndpointID: "ep_abc",
        Payload:    map[string]interface{}{"event": "user.created"},
    },
    {
        EndpointID: "ep_def",
        Payload:    map[string]interface{}{"event": "user.created"},
    },
})
if err != nil {
    log.Fatal(err)
}
for _, item := range batchResult.Items {
    if item.Error != nil {
        fmt.Printf("Item %d failed: %s\n", item.Index, item.Error.Message)
    } else {
        fmt.Printf("Item %d: delivery %s\n", item.Index, item.DeliveryID)
    }
}

// Fan-out multiple event types at once (max 20)
triggerBatchResult, err := c.TriggerBatch(ctx, []nahook.TriggerBatchItem{
    {
        EventType: "order.created",
        Payload:   map[string]interface{}{"orderId": "ord_1"},
    },
    {
        EventType: "invoice.paid",
        Payload:   map[string]interface{}{"invoiceId": "inv_1"},
    },
})
Management Client

Use the management package to administer workspaces, endpoints, event types, applications, subscriptions, and portal sessions.

package main

import (
    "context"
    "fmt"
    "log"

    nahook "github.com/getnahook/nahook-go"
    "github.com/getnahook/nahook-go/management"
)

func main() {
    mgmt, err := management.New("nhm_your_management_token")
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()
    workspaceID := "ws_abc123"

    // ── Endpoints ──

    // List all endpoints
    endpoints, err := mgmt.Endpoints.List(ctx, workspaceID)
    if err != nil {
        log.Fatal(err)
    }
    for _, ep := range endpoints.Data {
        fmt.Printf("Endpoint: %s -> %s (active: %v)\n", ep.ID, ep.URL, ep.IsActive)
    }

    // Create an endpoint
    newEp, err := mgmt.Endpoints.Create(ctx, workspaceID, nahook.CreateEndpointOptions{
        URL:         "https://example.com/webhooks",
        Description: "Production webhook receiver",
        Metadata:    map[string]string{"env": "production"},
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created endpoint: %s\n", newEp.ID)

    // Get an endpoint
    ep, err := mgmt.Endpoints.Get(ctx, workspaceID, newEp.ID)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Endpoint: %s\n", ep.URL)

    // Update an endpoint
    active := false
    updated, err := mgmt.Endpoints.Update(ctx, workspaceID, newEp.ID, nahook.UpdateEndpointOptions{
        IsActive: &active,
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Updated endpoint active: %v\n", updated.IsActive)

    // Delete an endpoint
    err = mgmt.Endpoints.Delete(ctx, workspaceID, newEp.ID)
    if err != nil {
        log.Fatal(err)
    }

    // ── Event Types ──

    // List event types
    eventTypes, err := mgmt.EventTypes.List(ctx, workspaceID)
    if err != nil {
        log.Fatal(err)
    }
    for _, et := range eventTypes.Data {
        fmt.Printf("Event type: %s (%s)\n", et.Name, et.ID)
    }

    // Create an event type
    newET, err := mgmt.EventTypes.Create(ctx, workspaceID, nahook.CreateEventTypeOptions{
        Name:        "order.shipped",
        Description: "Fired when an order ships",
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created event type: %s\n", newET.ID)

    // Get, update, delete follow the same pattern...

    // ── Applications ──

    // List with pagination
    limit := 10
    apps, err := mgmt.Applications.List(ctx, workspaceID, &nahook.ListOptions{
        Limit: &limit,
    })
    if err != nil {
        log.Fatal(err)
    }
    for _, app := range apps.Data {
        fmt.Printf("App: %s (%s)\n", app.Name, app.ID)
    }

    // Create an application
    newApp, err := mgmt.Applications.Create(ctx, workspaceID, nahook.CreateApplicationOptions{
        Name:       "Acme Corp",
        ExternalID: "customer_123",
        Metadata:   map[string]string{"plan": "enterprise"},
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created app: %s\n", newApp.ID)

    // List endpoints for an application
    appEndpoints, err := mgmt.Applications.ListEndpoints(ctx, workspaceID, newApp.ID)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("App has %d endpoints\n", len(appEndpoints.Data))

    // Create endpoint under an application
    appEp, err := mgmt.Applications.CreateEndpoint(ctx, workspaceID, newApp.ID, nahook.CreateEndpointOptions{
        URL: "https://acme.com/webhooks",
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created app endpoint: %s\n", appEp.ID)

    // ── Subscriptions ──

    // List subscriptions for an endpoint
    subs, err := mgmt.Subscriptions.List(ctx, workspaceID, appEp.ID)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Endpoint has %d subscriptions\n", len(subs.Data))

    // Create a subscription
    sub, err := mgmt.Subscriptions.Create(ctx, workspaceID, appEp.ID, nahook.CreateSubscriptionOptions{
        EventTypeID: newET.ID,
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created subscription: %s\n", sub.ID)

    // Delete a subscription
    err = mgmt.Subscriptions.Delete(ctx, workspaceID, appEp.ID, newET.ID)
    if err != nil {
        log.Fatal(err)
    }

    // ── Portal Sessions ──

    // Create a portal session for an application
    session, err := mgmt.PortalSessions.Create(ctx, workspaceID, newApp.ID, &nahook.CreatePortalSessionOptions{
        Metadata: map[string]string{"userId": "user_456"},
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Portal URL: %s (expires: %s)\n", session.URL, session.ExpiresAt)

    // Create without options
    session2, err := mgmt.PortalSessions.Create(ctx, workspaceID, newApp.ID, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Portal URL: %s\n", session2.URL)

    // ── Environments ──

    // List environments
    envs, err := mgmt.Environments.List(ctx, workspaceID)
    if err != nil {
        log.Fatal(err)
    }
    for _, env := range envs.Data {
        fmt.Printf("Env: %s (%s, default: %v)\n", env.Name, env.Slug, env.IsDefault)
    }

    // Create an environment
    newEnv, err := mgmt.Environments.Create(ctx, workspaceID, nahook.CreateEnvironmentOptions{
        Name: "Staging",
        Slug: "staging",
    })

    // Update
    updatedName := "Pre-production"
    mgmt.Environments.Update(ctx, workspaceID, newEnv.ID, nahook.UpdateEnvironmentOptions{
        Name: &updatedName,
    })

    // Delete
    mgmt.Environments.Delete(ctx, workspaceID, newEnv.ID)

    // ── Event Type Visibility ──

    // List visibility for an environment
    vis, err := mgmt.Environments.ListEventTypeVisibility(ctx, workspaceID, newEnv.ID)

    // Set event type as published in an environment
    entry, err := mgmt.Environments.SetEventTypeVisibility(ctx, workspaceID, newEnv.ID, newET.ID, nahook.SetVisibilityOptions{
        Published: true,
    })
}
Deliveries

Read access to a workspace's webhook deliveries — paginated list scoped to an endpoint, single-delivery metadata with an optional payload envelope, and the list of HTTP attempts behind a delivery.

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    nahook "github.com/getnahook/nahook-go"
    "github.com/getnahook/nahook-go/management"
)

func main() {
    mgmt, err := management.New("nhm_your_management_token")
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()
    workspaceID := "ws_abc123"
    endpointID := "ep_abc123"

    // ── List deliveries (paginated, newest-first) ──
    //
    // NextCursor is an opaque server-encrypted token — pass it back on the
    // next call verbatim. It is nil when there are no more pages.
    limit := 50
    page, err := mgmt.Deliveries.List(ctx, workspaceID, endpointID, &nahook.ListDeliveriesOptions{
        Limit: &limit,
    })
    if err != nil {
        log.Fatal(err)
    }
    for _, d := range page.Data {
        fmt.Printf("Delivery %s status=%s attempts=%d\n", d.ID, d.Status, d.TotalAttempts)
    }
    if page.NextCursor != nil {
        nextPage, _ := mgmt.Deliveries.List(ctx, workspaceID, endpointID, &nahook.ListDeliveriesOptions{
            Limit:  &limit,
            Cursor: *page.NextCursor,
        })
        fmt.Printf("Next page has %d more deliveries\n", len(nextPage.Data))
    }

    // ── Filter by status ──
    failed, err := mgmt.Deliveries.List(ctx, workspaceID, endpointID, &nahook.ListDeliveriesOptions{
        Status: "failed",
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%d failed deliveries\n", len(failed.Data))

    // ── Get a single delivery's metadata ──
    delivery, err := mgmt.Deliveries.Get(ctx, workspaceID, "del_abc123", nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Delivery %s endpoint=%s hasPayload=%v\n",
        delivery.ID, delivery.EndpointID, delivery.HasPayload)

    // ── Get with payload envelope ──
    //
    // The envelope is a tagged union: inspect Status before reading Data.
    // The four non-"available" statuses are returned with HTTP 200 — they
    // are not errors, they describe why the payload could not be returned.
    withPayload, err := mgmt.Deliveries.Get(ctx, workspaceID, "del_abc123", &nahook.GetDeliveryOptions{
        IncludePayload: true,
    })
    if err != nil {
        log.Fatal(err)
    }
    if withPayload.Payload != nil {
        switch withPayload.Payload.Status {
        case "available":
            var body map[string]interface{}
            if err := json.Unmarshal(withPayload.Payload.Data, &body); err == nil {
                fmt.Printf("Payload (%s): %v\n", withPayload.Payload.ContentType, body)
            }
        case "forbidden":
            fmt.Println("Payload storage not included in this workspace's plan")
        case "processing":
            fmt.Println("Delivery still in flight, try again shortly")
        case "not_found":
            fmt.Println("No stored payload for this delivery")
        case "error":
            fmt.Println("Transient infrastructure failure reading the payload")
        }
    }

    // ── List attempts (chronological, oldest first) ──
    attempts, err := mgmt.Deliveries.GetAttempts(ctx, workspaceID, "del_abc123")
    if err != nil {
        log.Fatal(err)
    }
    for _, a := range attempts {
        statusCode := "n/a"
        if a.ResponseStatusCode != nil {
            statusCode = fmt.Sprintf("%d", *a.ResponseStatusCode)
        }
        fmt.Printf("Attempt #%d status=%s response=%s\n",
            a.AttemptNumber, a.Status, statusCode)
    }
}
Error Handling
result, err := c.Send(ctx, "ep_123", nahook.SendOptions{
    Payload: map[string]interface{}{"test": true},
})
if err != nil {
    switch e := err.(type) {
    case *nahook.APIError:
        fmt.Printf("API error %d: %s (code: %s)\n", e.Status, e.Message, e.Code)

        if e.IsAuthError() {
            // 401 or 403 with token_disabled
            log.Fatal("Check your API key")
        }
        if e.IsNotFound() {
            // 404
            log.Fatal("Endpoint does not exist")
        }
        if e.IsRateLimited() {
            // 429 — RetryAfter may be set
            if e.RetryAfter != nil {
                fmt.Printf("Retry after %d seconds\n", *e.RetryAfter)
            }
        }
        if e.IsValidationError() {
            // 400
            fmt.Printf("Validation: %s\n", e.Message)
        }
        if e.IsRetryable() {
            // 5xx or 429 — consider retrying
        }

    case *nahook.NetworkError:
        fmt.Printf("Network error: %v\n", e.Cause)

    case *nahook.TimeoutError:
        fmt.Printf("Timed out after %dms\n", e.TimeoutMs)
    }
}
Custom Idempotency Key
// Provide your own idempotency key to deduplicate sends
result, err := c.Send(ctx, "ep_123", nahook.SendOptions{
    Payload:        map[string]interface{}{"orderId": "ord_123"},
    IdempotencyKey: "my-unique-key-abc",
})
// If not provided, a UUID v4 is generated automatically

Configuration

Client Options
Option Default Description
WithBaseURL(url) https://api.nahook.com API base URL
WithTimeout(d) 30s HTTP request timeout
WithRetries(n) 0 Max retries for retryable errors (5xx, 429, network)
WithHTTPClient(c) tuned default Caller-owned *http.Client (see below)
Management Options
Option Default Description
WithBaseURL(url) https://api.nahook.com API base URL
WithTimeout(d) 30s HTTP request timeout
WithHTTPClient(c) tuned default Caller-owned *http.Client (see below)

The management client does not support retries.

Advanced HTTP configuration

The SDK ships with a *http.Client backed by a tuned *http.Transport:

Setting Value
MaxIdleConnsPerHost 50
MaxIdleConns 100
IdleConnTimeout 90s
ForceAttemptHTTP2 true
Dialer.KeepAlive 30s

Go's http.DefaultTransport allows only 2 idle conns per host — fine for a script, expensive for a service that fans out webhooks in bursts (every send tears down and re-opens a connection). The tuned defaults are sized for moderate concurrent throughput.

For full control, supply your own *http.Client:

import (
    "net/http"
    "time"

    "github.com/getnahook/nahook-go/client"
)

custom := &http.Client{
    Timeout: 15 * time.Second,
    Transport: &http.Transport{
        // Don't forget Proxy: http.ProxyFromEnvironment if you want
        // HTTP_PROXY / HTTPS_PROXY env support — handcrafted Transports
        // drop the default's proxy wiring.
        Proxy: http.ProxyFromEnvironment,
        // Your own pool sizing, mTLS, custom RoundTripper, etc.
        MaxIdleConnsPerHost: 200,
        IdleConnTimeout:     60 * time.Second,
        ForceAttemptHTTP2:   true,
    },
}

c, err := client.New("nhk_us_...",
    client.WithHTTPClient(custom),
)

When WithHTTPClient is supplied:

  • The SDK uses your client verbatim and does not mutate it (good for shared clients).
  • Your http.Client.Timeout governs request timeouts and is what TimeoutError.TimeoutMs reports. If you set Timeout: 0 (Go's "no timeout"), TimeoutError.TimeoutMs will be 0 in any error report — set a concrete timeout if you care about the reported value.
  • WithTimeout is silently ignored — your client's Timeout wins.
  • You own its lifecycle. Client.Close() is a no-op in this case — call CloseIdleConnections() on your own transport when you want to drain.
Graceful shutdown — Close()
c, err := client.New("nhk_us_...")
if err != nil {
    log.Fatal(err)
}
defer c.Close()

Close() drains the SDK-owned *http.Transport's idle connection pool. Idempotent and cheap — safe in defer blocks, graceful shutdown handlers, or before recycling a long-lived client. It's a no-op when a custom *http.Client was supplied via WithHTTPClient, since that transport's lifecycle belongs to the caller.

management.Management exposes the same Close() method.

Skipping Close() is fine for short-lived scripts — the OS reaps sockets on process exit — but matters for test harnesses and long-running services where you want connections drained at known points.

Wrap your http.RoundTripper to plug in OpenTelemetry, Datadog, custom retry logic, or auth refresh — the SDK only ever calls Do(req) on the supplied client, so any standard middleware composes cleanly. The same WithHTTPClient option is available on the management client.

Retry Behavior

When retries are enabled (client only):

  • Retryable errors: 5xx, 429, network errors, timeouts
  • Non-retryable errors: 400, 401, 403, 404, 409, 413
  • Backoff: exponential with full jitter, base 500ms, max 10s
  • Formula: min(10s, 500ms * 2^attempt) * rand()
  • Respects Retry-After header when present

Auth

  • Client (ingestion): API keys starting with nhk_
  • Management: Management tokens starting with nhm_

Both will return an error at construction time if the prefix is invalid.

License

MIT

Documentation

Overview

Package nahook provides shared types, errors, and an internal HTTP client for the Nahook webhook platform SDKs.

Index

Constants

View Source
const (
	DefaultBaseURL = "https://api.nahook.com"
	DefaultTimeout = 30 * time.Second
	DefaultRetries = 0
)

Variables

This section is empty.

Functions

func PathEncode

func PathEncode(s string) string

PathEncode encodes a path segment for use in URLs. Internal: not part of the public API.

func ResolveBaseURL

func ResolveBaseURL(apiKey string) string

ResolveBaseURL extracts the region slug from an nhk_ API key and returns the regional base URL. Falls back to DefaultBaseURL for legacy keys.

Types

type APIError

type APIError struct {
	Status     int
	Code       string
	Message    string
	RetryAfter *int
}

APIError represents an error response from the Nahook API.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) IsAuthError

func (e *APIError) IsAuthError() bool

IsAuthError returns true for 401 or 403 with code "token_disabled".

func (*APIError) IsNotFound

func (e *APIError) IsNotFound() bool

IsNotFound returns true for 404 status codes.

func (*APIError) IsRateLimited

func (e *APIError) IsRateLimited() bool

IsRateLimited returns true for 429 status codes.

func (*APIError) IsRetryable

func (e *APIError) IsRetryable() bool

IsRetryable returns true for 5xx and 429 status codes.

func (*APIError) IsValidationError

func (e *APIError) IsValidationError() bool

IsValidationError returns true for 400 status codes.

type Application

type Application struct {
	ID         string            `json:"id"`
	ExternalID *string           `json:"externalId"`
	Name       string            `json:"name"`
	Metadata   map[string]string `json:"metadata"`
	// MaxEndpoints is the maximum number of endpoints this application may
	// have (disabled endpoints count). nil means unlimited.
	MaxEndpoints *int `json:"maxEndpoints"`
	// ShowEventTypes reports whether the Developer Portal exposes the
	// event-type catalog to this application.
	ShowEventTypes bool   `json:"showEventTypes"`
	CreatedAt      string `json:"createdAt"`
	UpdatedAt      string `json:"updatedAt"`
}

Application represents a developer application.

func (*Application) UnmarshalJSON added in v0.3.0

func (a *Application) UnmarshalJSON(data []byte) error

UnmarshalJSON applies the server default (true) to ShowEventTypes when the field is absent from a response, matching the other SDKs' fallback.

type BatchItemError

type BatchItemError struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

BatchItemError is an error for a specific item in a batch.

type BatchResult

type BatchResult struct {
	Items []BatchResultItem `json:"items"`
}

BatchResult is the response from a batch operation.

type BatchResultItem

type BatchResultItem struct {
	Index          int             `json:"index"`
	DeliveryID     string          `json:"deliveryId,omitempty"`
	IdempotencyKey string          `json:"idempotencyKey,omitempty"`
	EventTypeID    string          `json:"eventTypeId,omitempty"`
	DeliveryIDs    []string        `json:"deliveryIds,omitempty"`
	Status         string          `json:"status,omitempty"`
	Error          *BatchItemError `json:"error,omitempty"`
}

BatchResultItem is the result for one item in a batch operation.

type CreateApplicationOptions

type CreateApplicationOptions struct {
	Name       string            `json:"name"`
	ExternalID string            `json:"externalId,omitempty"`
	Metadata   map[string]string `json:"metadata,omitempty"`
	// MaxEndpoints caps how many endpoints this application may have
	// (disabled endpoints count). 0 makes the application read-only.
	// nil (omitted) means unlimited.
	MaxEndpoints *int `json:"maxEndpoints,omitempty"`
	// ShowEventTypes controls whether the Developer Portal exposes the
	// event-type catalog. nil (omitted) defaults to true.
	ShowEventTypes *bool `json:"showEventTypes,omitempty"`
}

CreateApplicationOptions configures a new application.

type CreateEndpointOptions

type CreateEndpointOptions struct {
	URL          string                 `json:"url"`
	Type         string                 `json:"type,omitempty"`
	Description  string                 `json:"description,omitempty"`
	Metadata     map[string]string      `json:"metadata,omitempty"`
	Config       map[string]interface{} `json:"config,omitempty"`
	AuthUsername string                 `json:"authUsername,omitempty"`
	AuthPassword string                 `json:"authPassword,omitempty"`
	// EnvironmentID is optional. Public id (e.g. "env_abc123") of the environment
	// to scope this endpoint. If omitted, the workspace's default environment is used.
	EnvironmentID string `json:"environmentId,omitempty"`
}

CreateEndpointOptions configures a new endpoint.

type CreateEnvironmentOptions

type CreateEnvironmentOptions struct {
	Name string `json:"name"`
	Slug string `json:"slug"`
}

CreateEnvironmentOptions configures a new environment.

type CreateEventTypeOptions

type CreateEventTypeOptions struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
}

CreateEventTypeOptions configures a new event type.

type CreatePortalSessionOptions

type CreatePortalSessionOptions struct {
	Metadata         map[string]string `json:"metadata,omitempty"`
	Role             string            `json:"role,omitempty"`
	ExpiresInMinutes int               `json:"expiresInMinutes,omitempty"`
}

CreatePortalSessionOptions configures a new portal session.

type CreateSubscriptionOptions

type CreateSubscriptionOptions struct {
	EventTypeIDs []string `json:"eventTypeIds"`
}

CreateSubscriptionOptions configures a new subscription (bulk).

type Delivery added in v0.2.0

type Delivery struct {
	ID             string  `json:"id"`
	IdempotencyKey string  `json:"idempotencyKey"`
	EndpointID     string  `json:"endpointId"`
	Status         string  `json:"status"`
	TotalAttempts  int     `json:"totalAttempts"`
	FirstAttemptAt *string `json:"firstAttemptAt"`
	DeliveredAt    *string `json:"deliveredAt"`
	NextRetryAt    *string `json:"nextRetryAt"`
	HasPayload     bool    `json:"hasPayload"`
	CreatedAt      string  `json:"createdAt"`
	UpdatedAt      string  `json:"updatedAt"`
}

Delivery represents a webhook delivery's metadata (no payload body).

type DeliveryAttempt added in v0.2.0

type DeliveryAttempt struct {
	ID                 string  `json:"id"`
	AttemptNumber      int     `json:"attemptNumber"`
	Status             string  `json:"status"`
	ResponseStatusCode *int    `json:"responseStatusCode"`
	ResponseTimeMs     *int    `json:"responseTimeMs"`
	ErrorMessage       *string `json:"errorMessage"`
	CreatedAt          string  `json:"createdAt"`
}

DeliveryAttempt represents one HTTP delivery attempt against an endpoint. Status is an opaque worker-emitted string (e.g. "success", "failed") — do not model it as an enum, the set may evolve.

type DeliveryStatus added in v0.2.0

type DeliveryStatus = string

DeliveryStatus enumerates the lifecycle states of a webhook delivery. Possible values: "pending", "delivering", "delivered", "scheduled_retry", "failed", "dead_letter".

type DeliveryWithPayload added in v0.2.0

type DeliveryWithPayload struct {
	Delivery
	Payload *PayloadEnvelope `json:"payload,omitempty"`
}

DeliveryWithPayload is the response shape from get() — Delivery metadata, plus an optional payload envelope when the request included ?include=payload.

type Endpoint

type Endpoint struct {
	ID          string                 `json:"id"`
	URL         string                 `json:"url"`
	Description *string                `json:"description"`
	IsActive    bool                   `json:"isActive"`
	Type        string                 `json:"type"`
	Config      map[string]interface{} `json:"config"`
	Secret      string                 `json:"secret,omitempty"`
	Metadata    map[string]string      `json:"metadata,omitempty"`
	CreatedAt   string                 `json:"createdAt"`
	UpdatedAt   string                 `json:"updatedAt"`
}

Endpoint represents a webhook endpoint.

type Environment

type Environment struct {
	ID        string `json:"id"`
	Name      string `json:"name"`
	Slug      string `json:"slug"`
	IsDefault bool   `json:"isDefault"`
	CreatedAt string `json:"createdAt"`
	UpdatedAt string `json:"updatedAt"`
}

Environment represents a workspace environment.

type EventType

type EventType struct {
	ID          string  `json:"id"`
	Name        string  `json:"name"`
	Description *string `json:"description"`
	CreatedAt   string  `json:"createdAt"`
}

EventType represents a registered event type.

type EventTypeVisibility

type EventTypeVisibility struct {
	EventTypeID   string `json:"eventTypeId"`
	EventTypeName string `json:"eventTypeName"`
	Published     bool   `json:"published"`
}

EventTypeVisibility represents the visibility of an event type in an environment.

type GetDeliveryOptions added in v0.2.0

type GetDeliveryOptions struct {
	IncludePayload bool
}

GetDeliveryOptions configures a single delivery fetch. Set IncludePayload to true to request the payload envelope alongside metadata.

type HTTPClient

type HTTPClient struct {
	// contains filtered or unexported fields
}

HTTPClient is the internal HTTP client shared by the client and management packages. Internal: not part of the public API.

func NewHTTPClient

func NewHTTPClient(cfg HTTPClientConfig) *HTTPClient

NewHTTPClient creates a new internal HTTP client. Internal: not part of the public API.

func (*HTTPClient) Close added in v0.2.1

func (c *HTTPClient) Close()

Close drains the SDK-owned *http.Transport's idle connection pool. Useful for clean test teardown, graceful shutdown, or explicit reset before recycling long-lived clients. Idempotent. No-op when a caller-owned *http.Client was supplied via HTTPClientConfig.HTTPClient — the caller owns that transport's lifecycle.

func (*HTTPClient) HTTPClient added in v0.2.0

func (c *HTTPClient) HTTPClient() *http.Client

HTTPClient returns the underlying *http.Client. Useful for callers who want to introspect or attach instrumentation. Mutating the returned client affects all subsequent SDK requests.

func (*HTTPClient) Request

func (c *HTTPClient) Request(ctx context.Context, opts RequestOptions, result interface{}) error

Request performs an HTTP request and decodes the JSON response into result. For DELETE (204) responses, result may be nil.

func (*HTTPClient) RequestWithStatus

func (c *HTTPClient) RequestWithStatus(ctx context.Context, opts RequestOptions, result interface{}) (int, error)

RequestWithStatus performs an HTTP request and returns the status code along with the decoded body.

type HTTPClientConfig

type HTTPClientConfig struct {
	Token   string
	BaseURL string
	Timeout time.Duration
	Retries int
	// HTTPClient, when non-nil, is used verbatim and not mutated. The caller's
	// HTTPClient.Timeout governs request timeouts and is what TimeoutError.TimeoutMs
	// reports. When nil, the SDK builds a *http.Client with a tuned *http.Transport
	// (HTTP/2, TCP keep-alive, MaxIdleConnsPerHost = 50).
	HTTPClient *http.Client
}

HTTPClientConfig configures the internal HTTP client. Internal: not part of the public API.

type ListDeliveriesOptions added in v0.2.0

type ListDeliveriesOptions struct {
	Limit  *int
	Cursor string
	Status string
}

ListDeliveriesOptions configures a deliveries list query. All fields are optional. Cursor is an opaque token from a previous PaginatedResult's NextCursor — pass it through verbatim.

type ListOptions

type ListOptions struct {
	Limit  *int
	Offset *int
}

ListOptions configures pagination for list operations.

type ListResult

type ListResult[T any] struct {
	Data []T `json:"data"`
}

ListResult wraps a list response.

type NetworkError

type NetworkError struct {
	Cause error
}

NetworkError represents a network-level failure where no HTTP response was received.

func (*NetworkError) Error

func (e *NetworkError) Error() string

func (*NetworkError) Unwrap

func (e *NetworkError) Unwrap() error

type NullableInt added in v0.3.0

type NullableInt struct {
	// Value is the number to send; nil marshals as JSON null.
	Value *int
}

NullableInt is a JSON field that marshals as either a number or an explicit null. PATCH fields typed *NullableInt are tri-state: a nil pointer is omitted from the body entirely (leave unchanged), IntNull() marshals as null (clear), and IntValue(n) marshals as n (set).

func IntNull added in v0.3.0

func IntNull() *NullableInt

IntNull returns a NullableInt that marshals as explicit JSON null — on UpdateApplicationOptions.MaxEndpoints this clears the cap (unlimited).

func IntValue added in v0.3.0

func IntValue(v int) *NullableInt

IntValue returns a NullableInt carrying v.

func (NullableInt) MarshalJSON added in v0.3.0

func (n NullableInt) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

func (*NullableInt) UnmarshalJSON added in v0.3.0

func (n *NullableInt) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler.

type PaginatedResult added in v0.2.0

type PaginatedResult[T any] struct {
	Data       []T     `json:"data"`
	NextCursor *string `json:"nextCursor"`
}

PaginatedResult is a generic cursor-paginated read result. NextCursor is an opaque, server-encrypted token — pass it back verbatim on the next request, do not decode or modify it. Nil when there are no more pages.

type PayloadEnvelope added in v0.2.0

type PayloadEnvelope struct {
	Status      string          `json:"status"`
	Data        json.RawMessage `json:"data,omitempty"`
	ContentType string          `json:"contentType,omitempty"`
}

PayloadEnvelope is a flat tagged union describing the access state of a stored delivery payload. The Status field discriminates which other fields are populated:

  • "available": Data and ContentType are set.
  • "forbidden": workspace plan does not include payload storage.
  • "processing": delivery still in flight, payload not yet written.
  • "not_found": terminal delivery without a stored payload.
  • "error": transient infrastructure failure reading the payload.

Only "available" is a successful read; all four other statuses are returned with HTTP 200 — do not treat them as errors.

type PortalSession

type PortalSession struct {
	URL       string `json:"url"`
	Code      string `json:"code"`
	ExpiresAt string `json:"expiresAt"`
}

PortalSession represents a portal session for developer self-service.

type RequestOptions

type RequestOptions struct {
	Method string
	Path   string
	Body   interface{}
	Query  map[string]string
}

RequestOptions describes an HTTP request to the Nahook API. Internal: not part of the public API.

type SendBatchItem

type SendBatchItem struct {
	EndpointID     string                 `json:"endpointId"`
	Payload        map[string]interface{} `json:"payload"`
	IdempotencyKey string                 `json:"idempotencyKey,omitempty"`
}

SendBatchItem represents one item in a batch send.

type SendOptions

type SendOptions struct {
	Payload        map[string]interface{} `json:"payload"`
	IdempotencyKey string                 `json:"idempotencyKey,omitempty"`
}

SendOptions configures a direct send to a specific endpoint.

type SendResult

type SendResult struct {
	DeliveryID     string `json:"deliveryId"`
	IdempotencyKey string `json:"idempotencyKey"`
	Status         string `json:"status"`
}

SendResult is the response from a direct send.

type SetVisibilityOptions

type SetVisibilityOptions struct {
	Published bool `json:"published"`
}

SetVisibilityOptions configures event type visibility in an environment.

type SubscribeResult

type SubscribeResult struct {
	Subscribed int `json:"subscribed"`
}

SubscribeResult is the response from subscribing an endpoint to event types.

type Subscription

type Subscription struct {
	ID            string `json:"id"`
	EventTypeID   string `json:"eventTypeId"`
	EventTypeName string `json:"eventTypeName"`
	CreatedAt     string `json:"createdAt"`
}

Subscription represents an event type subscription on an endpoint.

type TimeoutError

type TimeoutError struct {
	TimeoutMs int
}

TimeoutError represents a request that exceeded the configured timeout.

func (*TimeoutError) Error

func (e *TimeoutError) Error() string

type TriggerBatchItem

type TriggerBatchItem struct {
	EventType string                 `json:"eventType"`
	Payload   map[string]interface{} `json:"payload"`
	Metadata  map[string]string      `json:"metadata,omitempty"`
}

TriggerBatchItem represents one item in a batch trigger.

type TriggerOptions

type TriggerOptions struct {
	Payload  map[string]interface{} `json:"payload"`
	Metadata map[string]string      `json:"metadata,omitempty"`
}

TriggerOptions configures a fan-out trigger by event type.

type TriggerResult

type TriggerResult struct {
	EventTypeID string   `json:"eventTypeId"`
	DeliveryIDs []string `json:"deliveryIds"`
	Status      string   `json:"status"`
}

TriggerResult is the response from a trigger.

type UpdateApplicationOptions

type UpdateApplicationOptions struct {
	Name     *string           `json:"name,omitempty"`
	Metadata map[string]string `json:"metadata,omitempty"`
	// MaxEndpoints is tri-state: leave nil to keep the current cap,
	// IntNull() to clear it (unlimited), or IntValue(n) to set it.
	MaxEndpoints *NullableInt `json:"maxEndpoints,omitempty"`
	// ShowEventTypes is omitted (unchanged) when nil.
	ShowEventTypes *bool `json:"showEventTypes,omitempty"`
}

UpdateApplicationOptions configures an application update.

type UpdateEndpointOptions

type UpdateEndpointOptions struct {
	URL         *string           `json:"url,omitempty"`
	Description *string           `json:"description,omitempty"`
	Metadata    map[string]string `json:"metadata,omitempty"`
	IsActive    *bool             `json:"isActive,omitempty"`
}

UpdateEndpointOptions configures an endpoint update.

type UpdateEnvironmentOptions

type UpdateEnvironmentOptions struct {
	Name *string `json:"name,omitempty"`
}

UpdateEnvironmentOptions configures an environment update.

type UpdateEventTypeOptions

type UpdateEventTypeOptions struct {
	Description *string `json:"description,omitempty"`
}

UpdateEventTypeOptions configures an event type update.

Directories

Path Synopsis
Package client provides the Nahook ingestion client for sending webhooks.
Package client provides the Nahook ingestion client for sending webhooks.
Package management provides the Nahook management API client for administering workspaces, endpoints, event types, applications, subscriptions, and portal sessions.
Package management provides the Nahook management API client for administering workspaces, endpoints, event types, applications, subscriptions, and portal sessions.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL