volley

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Dec 17, 2025 License: MIT Imports: 8 Imported by: 0

README

Volley Go SDK

Official Go SDK for the Volley API. This SDK provides a convenient way to interact with the Volley webhook infrastructure API.

Volley is a webhook infrastructure platform that provides reliable webhook delivery, rate limiting, retries, monitoring, and more.

Resources

Installation

go get github.com/volleyhq/volley-go

Quick Start

package main

import (
    "fmt"
    "log"
    
    "github.com/volleyhooks/volley-go"
)

func main() {
    // Create a client with your API token
    client := volley.NewClient("your-api-token")
    
    // Optionally set organization context
    orgID := uint64(123)
    client.SetOrganizationID(orgID)
    
    // List organizations
    orgs, err := client.ListOrganizations()
    if err != nil {
        log.Fatal(err)
    }
    
    for _, org := range orgs {
        fmt.Printf("Organization: %s (ID: %d)\n", org.Name, org.ID)
    }
}

Authentication

Volley uses API tokens for authentication. These are long-lived tokens designed for programmatic access.

Getting Your API Token
  1. Log in to the Volley Console
  2. Navigate to Settings → Account → API Token
  3. Click View Token (you may need to verify your password)
  4. Copy the token and store it securely

Important: API tokens are non-expiring and provide full access to your account. Keep them secure and rotate them if compromised. See the Security Guide for best practices.

client := volley.NewClient("your-api-token")

For more details on authentication, API tokens, and security, see the Authentication Guide and Security Guide.

Organization Context

When you have multiple organizations, you need to specify which organization context to use for API requests. The API verifies that resources (like projects) belong to the specified organization.

You can set the organization context in two ways:

// Method 1: Set organization ID for all subsequent requests
client.SetOrganizationID(123)

// Method 2: Create client with organization ID
client := volley.NewClient("your-api-token", 
    volley.WithOrganizationID(123),
)

// Clear organization context (uses first accessible organization)
client.ClearOrganizationID()

Note: If you don't set an organization ID, the API uses your first accessible organization by default. For more details, see the API Reference - Organization Context.

Examples

Organizations
// List all organizations
orgs, err := client.ListOrganizations()
if err != nil {
    log.Fatal(err)
}

// Get current organization
org, err := client.GetOrganization(nil) // nil = use default
if err != nil {
    log.Fatal(err)
}

// Create organization
newOrg, err := client.CreateOrganization(volley.CreateOrganizationRequest{
    Name: "My Organization",
})
if err != nil {
    log.Fatal(err)
}
Projects
// List projects
projects, err := client.ListProjects()
if err != nil {
    log.Fatal(err)
}

// Create project
project, err := client.CreateProject(volley.CreateProjectRequest{
    Name:      "My Project",
    IsDefault: false,
})
if err != nil {
    log.Fatal(err)
}

// Update project
updated, err := client.UpdateProject(project.ID, volley.UpdateProjectRequest{
    Name: "Updated Name",
})
if err != nil {
    log.Fatal(err)
}

// Delete project
err = client.DeleteProject(project.ID)
if err != nil {
    log.Fatal(err)
}
Sources
// List sources in a project
sources, err := client.ListSources(projectID)
if err != nil {
    log.Fatal(err)
}

// Create source
source, err := client.CreateSource(projectID, volley.CreateSourceRequest{
    Name:     "Stripe Webhooks",
    EPS:      10,
    AuthType: "none",
})
if err != nil {
    log.Fatal(err)
}

// Get source details
source, err := client.GetSource(sourceID)
if err != nil {
    log.Fatal(err)
}

// Update source
updated, err := client.UpdateSource(sourceID, volley.UpdateSourceRequest{
    Name: "Updated Source Name",
    EPS:  &[]int{20}[0],
})
if err != nil {
    log.Fatal(err)
}
Destinations
// List destinations
destinations, err := client.ListDestinations(projectID)
if err != nil {
    log.Fatal(err)
}

// Create destination
dest, err := client.CreateDestination(projectID, volley.CreateDestinationRequest{
    Name: "Production Endpoint",
    URL:  "https://api.example.com/webhooks",
    EPS:  5,
})
if err != nil {
    log.Fatal(err)
}
Connections
// List connections
connections, err := client.GetConnections(projectID)
if err != nil {
    log.Fatal(err)
}

// Create connection
conn, err := client.CreateConnection(projectID, volley.CreateConnectionRequest{
    SourceID:      sourceID,
    DestinationID: destID,
    Status:        "enabled",
    EPS:           5,
    MaxRetries:    3,
})
if err != nil {
    log.Fatal(err)
}
Events
// List events with filters
events, err := client.ListEvents(projectID, &volley.ListEventsOptions{
    Status:   "failed",
    SourceID: &sourceID,
    Limit:    &[]int{50}[0],
    Offset:   &[]int{0}[0],
})
if err != nil {
    log.Fatal(err)
}

// Get event details
event, err := client.GetEvent(requestID)
if err != nil {
    log.Fatal(err)
}

// Replay failed event
result, err := client.ReplayEvent(volley.ReplayEventRequest{
    EventID: "evt_abc123def456",
})
if err != nil {
    log.Fatal(err)
}
Delivery Attempts
// List delivery attempts
attempts, err := client.ListDeliveryAttempts(projectID, &volley.ListDeliveryAttemptsOptions{
    EventID: "evt_abc123",
    Status:  "failed",
    Limit:   &[]int{50}[0],
})
if err != nil {
    log.Fatal(err)
}
Sending Webhooks
// Send a webhook to a source
eventID, err := client.SendWebhook("source_ingestion_id", map[string]interface{}{
    "event": "user.created",
    "data": map[string]interface{}{
        "user_id": "123",
        "email":   "user@example.com",
    },
})
if err != nil {
    log.Fatal(err)
}

Error Handling

The SDK returns errors that implement the error interface. API errors are returned as *volley.APIError:

event, err := client.GetEvent(requestID)
if err != nil {
    if apiErr, ok := err.(*volley.APIError); ok {
        fmt.Printf("API Error: %s (Status: %d)\n", apiErr.ErrorMsg, apiErr.Status)
    } else {
        fmt.Printf("Error: %v\n", err)
    }
}
Common HTTP Status Codes
  • 200 - Success
  • 201 - Created
  • 202 - Accepted (webhook queued)
  • 400 - Bad Request (validation error)
  • 401 - Unauthorized (invalid or missing API token)
  • 403 - Forbidden (insufficient permissions)
  • 404 - Not Found
  • 429 - Rate Limit Exceeded
  • 500 - Internal Server Error

For more details on error responses, see the API Reference - Response Codes.

Client Options

You can configure the client with various options:

// Custom base URL (for testing)
client := volley.NewClient("token", 
    volley.WithBaseURL("https://api-staging.volleyhooks.com"),
)

// Custom HTTP client
httpClient := &http.Client{
    Timeout: 60 * time.Second,
}
client := volley.NewClient("token",
    volley.WithHTTPClient(httpClient),
)

Additional Resources

Documentation
Use Cases

Support

Testing

The SDK includes comprehensive unit tests and integration tests.

Running Unit Tests

Unit tests use a mock HTTP server and don't require API credentials:

go test ./...

To run tests with verbose output:

go test -v ./...
Running Integration Tests

Integration tests make real API calls to the Volley API. You'll need to set your API token:

export VOLLEY_API_TOKEN="your-api-token"
go test -v -run TestIntegration ./...

Note: Integration tests are skipped if VOLLEY_API_TOKEN is not set or if running in short mode (go test -short).

Test Coverage

To see test coverage:

go test -cover ./...

For detailed coverage report:

go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

When contributing:

  1. Add tests for new functionality
  2. Ensure all tests pass (go test ./...)
  3. Update documentation as needed

License

MIT License - see LICENSE file for details.

Documentation

Index

Constants

View Source
const (
	// DefaultBaseURL is the default Volley API base URL
	DefaultBaseURL = "https://api.volleyhooks.com"
	// DefaultTimeout is the default HTTP client timeout
	DefaultTimeout = 30 * time.Second
)
View Source
const Version = "1.0.1"

Version is the current version of the Volley Go SDK

Variables

This section is empty.

Functions

This section is empty.

Types

type APIError

type APIError struct {
	ErrorMsg string `json:"error"`
	Message  string `json:"message,omitempty"`
	Status   int    `json:"-"`
}

APIError represents an API error response

func (*APIError) Error

func (e *APIError) Error() string

type Client

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

Client is the main Volley API client

func NewClient

func NewClient(apiToken string, opts ...ClientOption) *Client

NewClient creates a new Volley API client

func (*Client) BaseURL

func (c *Client) BaseURL() string

BaseURL returns the base URL of the client (for testing)

func (*Client) ClearOrganizationID

func (c *Client) ClearOrganizationID()

ClearOrganizationID clears the organization ID

func (*Client) CreateConnection

func (c *Client) CreateConnection(projectID uint64, req CreateConnectionRequest) (*Connection, error)

CreateConnection creates a connection between a source and destination

func (*Client) CreateDestination

func (c *Client) CreateDestination(projectID uint64, req CreateDestinationRequest) (*Destination, error)

CreateDestination creates a new destination

func (*Client) CreateOrganization

func (c *Client) CreateOrganization(req CreateOrganizationRequest) (*Organization, error)

CreateOrganization creates a new organization

func (*Client) CreateProject

func (c *Client) CreateProject(req CreateProjectRequest) (*Project, error)

CreateProject creates a new project

func (*Client) CreateSource

func (c *Client) CreateSource(projectID uint64, req CreateSourceRequest) (*Source, error)

CreateSource creates a new source

func (*Client) DeleteConnection

func (c *Client) DeleteConnection(connectionID uint64) error

DeleteConnection deletes a connection

func (*Client) DeleteDestination

func (c *Client) DeleteDestination(destinationID uint64) error

DeleteDestination deletes a destination

func (*Client) DeleteProject

func (c *Client) DeleteProject(projectID uint64) error

DeleteProject deletes a project

func (*Client) DeleteSource

func (c *Client) DeleteSource(sourceID uint64) error

DeleteSource deletes a source

func (*Client) GetConnection

func (c *Client) GetConnection(connectionID uint64) (*Connection, error)

GetConnection gets details and metrics for a connection

func (*Client) GetConnections

func (c *Client) GetConnections(projectID uint64) ([]Connection, error)

GetConnections lists all connections in a project

func (*Client) GetDestination

func (c *Client) GetDestination(destinationID uint64) (*Destination, error)

GetDestination gets details of a specific destination

func (*Client) GetEvent

func (c *Client) GetEvent(requestID uint64) (*Event, error)

GetEvent gets detailed information about a specific event by its database ID

func (*Client) GetOrganization

func (c *Client) GetOrganization(organizationID *uint64) (*Organization, error)

GetOrganization gets the current organization If organizationID is provided, it will be used; otherwise, the first accessible organization is returned

func (*Client) GetSource

func (c *Client) GetSource(sourceID uint64) (*Source, error)

GetSource gets details of a specific source

func (*Client) ListDeliveryAttempts

func (c *Client) ListDeliveryAttempts(projectID uint64, opts *ListDeliveryAttemptsOptions) (*ListDeliveryAttemptsResponse, error)

ListDeliveryAttempts lists all delivery attempts for a project with optional filters

func (*Client) ListDestinations

func (c *Client) ListDestinations(projectID uint64) ([]Destination, error)

ListDestinations lists all destinations in a project

func (*Client) ListEvents

func (c *Client) ListEvents(projectID uint64, opts *ListEventsOptions) (*ListEventsResponse, error)

ListEvents lists all events/requests for a project with optional filters

func (*Client) ListOrganizations

func (c *Client) ListOrganizations() ([]Organization, error)

ListOrganizations lists all organizations the user has access to

func (*Client) ListProjects

func (c *Client) ListProjects() ([]Project, error)

ListProjects lists all projects in the current organization

func (*Client) ListSources

func (c *Client) ListSources(projectID uint64) ([]Source, error)

ListSources lists all sources in a project

func (*Client) OrganizationID

func (c *Client) OrganizationID() *uint64

OrganizationID returns the organization ID (for testing)

func (*Client) ReplayEvent

func (c *Client) ReplayEvent(req ReplayEventRequest) (*ReplayEventResponse, error)

ReplayEvent replays a failed event by its event_id

func (*Client) SendWebhook

func (c *Client) SendWebhook(sourceID string, payload interface{}) (string, error)

SendWebhook sends a webhook to a source The sourceID is the ingestion ID provided when you create a source

func (*Client) SetOrganizationID

func (c *Client) SetOrganizationID(orgID uint64)

SetOrganizationID sets the organization ID for subsequent requests

func (*Client) UpdateConnection

func (c *Client) UpdateConnection(connectionID uint64, req UpdateConnectionRequest) (*Connection, error)

UpdateConnection updates a connection

func (*Client) UpdateDestination

func (c *Client) UpdateDestination(destinationID uint64, req UpdateDestinationRequest) (*Destination, error)

UpdateDestination updates a destination

func (*Client) UpdateProject

func (c *Client) UpdateProject(projectID uint64, req UpdateProjectRequest) (*Project, error)

UpdateProject updates a project's name

func (*Client) UpdateSource

func (c *Client) UpdateSource(sourceID uint64, req UpdateSourceRequest) (*Source, error)

UpdateSource updates a source

type ClientOption

type ClientOption func(*Client)

ClientOption is a function that configures a Client

func WithBaseURL

func WithBaseURL(baseURL string) ClientOption

WithBaseURL sets a custom base URL for the client

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) ClientOption

WithHTTPClient sets a custom HTTP client

func WithOrganizationID

func WithOrganizationID(orgID uint64) ClientOption

WithOrganizationID sets the organization ID for all requests

type Connection

type Connection struct {
	ID            uint64    `json:"id"`
	SourceID      uint64    `json:"source_id"`
	DestinationID uint64    `json:"destination_id"`
	Status        string    `json:"status"`
	EPS           int       `json:"eps"`
	MaxRetries    int       `json:"max_retries"`
	CreatedAt     time.Time `json:"created_at"`
	UpdatedAt     time.Time `json:"updated_at"`
}

Connection represents a connection between a source and destination

type CreateConnectionRequest

type CreateConnectionRequest struct {
	SourceID      uint64 `json:"source_id"`
	DestinationID uint64 `json:"destination_id"`
	Status        string `json:"status"` // "enabled" or "disabled"
	EPS           int    `json:"eps"`
	MaxRetries    int    `json:"max_retries"`
}

CreateConnectionRequest represents the request to create a connection

type CreateDestinationRequest

type CreateDestinationRequest struct {
	Name string `json:"name"`
	URL  string `json:"url"`
	EPS  int    `json:"eps"`
}

CreateDestinationRequest represents the request to create a destination

type CreateOrganizationRequest

type CreateOrganizationRequest struct {
	Name string `json:"name"`
}

CreateOrganizationRequest represents the request to create an organization

type CreateProjectRequest

type CreateProjectRequest struct {
	Name      string `json:"name"`
	IsDefault bool   `json:"is_default,omitempty"`
}

CreateProjectRequest represents the request to create a project

type CreateSourceRequest

type CreateSourceRequest struct {
	Name     string `json:"name"`
	EPS      int    `json:"eps"`
	AuthType string `json:"auth_type"` // "none", "basic", "api_key"
}

CreateSourceRequest represents the request to create a source

type DeliveryAttempt

type DeliveryAttempt struct {
	ID           uint64    `json:"id"`
	EventID      string    `json:"event_id"`
	ConnectionID uint64    `json:"connection_id"`
	Status       string    `json:"status"`
	StatusCode   int       `json:"status_code"`
	ErrorReason  string    `json:"error_reason,omitempty"`
	DurationMs   int64     `json:"duration_ms"`
	CreatedAt    time.Time `json:"created_at"`
}

DeliveryAttempt represents a delivery attempt for an event

type Destination

type Destination struct {
	ID        uint64    `json:"id"`
	Name      string    `json:"name"`
	URL       string    `json:"url"`
	EPS       int       `json:"eps"`
	Status    string    `json:"status"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

Destination represents a webhook destination

type Event

type Event struct {
	ID               uint64                 `json:"id"`
	EventID          string                 `json:"event_id"`
	SourceID         uint64                 `json:"source_id"`
	ProjectID        uint64                 `json:"project_id"`
	RawBody          string                 `json:"raw_body"`
	Headers          map[string]interface{} `json:"headers"`
	Status           string                 `json:"status"`
	DeliveryAttempts []DeliveryAttempt      `json:"delivery_attempts,omitempty"`
	CreatedAt        time.Time              `json:"created_at"`
}

Event represents a webhook event/request

type ListDeliveryAttemptsOptions

type ListDeliveryAttemptsOptions struct {
	EventID       string
	SourceID      *uint64
	DestinationID *uint64
	ConnectionID  *uint64
	Status        string // "success" or "failed"
	StartTime     *time.Time
	EndTime       *time.Time
	Sort          string // "time", "time_oldest", "duration", "status_code"
	Limit         *int
	Offset        *int
}

ListDeliveryAttemptsOptions represents options for listing delivery attempts

type ListDeliveryAttemptsResponse

type ListDeliveryAttemptsResponse struct {
	PaginatedResponse
	Attempts []DeliveryAttempt `json:"attempts"`
}

ListDeliveryAttemptsResponse represents the response from listing delivery attempts

type ListEventsOptions

type ListEventsOptions struct {
	SourceID      *uint64
	ConnectionID  *uint64
	DestinationID *uint64
	Status        string // "processed", "pending", "failed", "dropped"
	StartTime     *time.Time
	EndTime       *time.Time
	Search        string
	Limit         *int
	Offset        *int
}

ListEventsOptions represents options for listing events

type ListEventsResponse

type ListEventsResponse struct {
	PaginatedResponse
	Requests []Event `json:"requests"`
}

ListEventsResponse represents the response from listing events

type Organization

type Organization struct {
	ID        uint64    `json:"id"`
	Name      string    `json:"name"`
	Slug      string    `json:"slug"`
	AccountID uint64    `json:"account_id"`
	Role      string    `json:"role"`
	CreatedAt time.Time `json:"created_at"`
}

Organization represents a Volley organization

type PaginatedResponse

type PaginatedResponse struct {
	Total  int64 `json:"total"`
	Limit  int   `json:"limit"`
	Offset int   `json:"offset"`
}

PaginatedResponse represents a paginated API response

type Project

type Project struct {
	ID             uint64    `json:"id"`
	Name           string    `json:"name"`
	OrganizationID uint64    `json:"organization_id"`
	IsDefault      bool      `json:"is_default"`
	CreatedAt      time.Time `json:"created_at"`
	UpdatedAt      time.Time `json:"updated_at"`
}

Project represents a Volley project

type ReplayEventRequest

type ReplayEventRequest struct {
	EventID       string  `json:"event_id"`
	DestinationID *uint64 `json:"destination_id,omitempty"`
	ConnectionID  *uint64 `json:"connection_id,omitempty"`
}

ReplayEventRequest represents the request to replay an event

type ReplayEventResponse

type ReplayEventResponse struct {
	Success     bool   `json:"success"`
	Status      string `json:"status"`
	StatusCode  int    `json:"status_code"`
	ErrorReason string `json:"error_reason,omitempty"`
	DurationMs  int64  `json:"duration_ms"`
	AttemptID   uint64 `json:"attempt_id"`
}

ReplayEventResponse represents the response from replaying an event

type Source

type Source struct {
	ID               uint64    `json:"id"`
	Slug             string    `json:"slug"`
	IngestionID      string    `json:"ingestion_id"`
	Type             string    `json:"type"`
	EPS              int       `json:"eps"`
	Status           string    `json:"status"`
	ConnectionCount  int64     `json:"connection_count"`
	AuthType         string    `json:"auth_type"`
	VerifySignature  bool      `json:"verify_signature"`
	WebhookSecretSet bool      `json:"webhook_secret_set"`
	AuthUsername     string    `json:"auth_username,omitempty"`
	AuthKeyName      string    `json:"auth_key_name,omitempty"`
	CreatedAt        time.Time `json:"created_at"`
	UpdatedAt        time.Time `json:"updated_at"`
}

Source represents a webhook source

type UpdateConnectionRequest

type UpdateConnectionRequest struct {
	Status     string `json:"status,omitempty"` // "enabled" or "disabled"
	EPS        *int   `json:"eps,omitempty"`
	MaxRetries *int   `json:"max_retries,omitempty"`
}

UpdateConnectionRequest represents the request to update a connection

type UpdateDestinationRequest

type UpdateDestinationRequest struct {
	Name   string `json:"name,omitempty"`
	URL    string `json:"url,omitempty"`
	EPS    *int   `json:"eps,omitempty"`
	Status string `json:"status,omitempty"`
}

UpdateDestinationRequest represents the request to update a destination

type UpdateProjectRequest

type UpdateProjectRequest struct {
	Name string `json:"name"`
}

UpdateProjectRequest represents the request to update a project

type UpdateSourceRequest

type UpdateSourceRequest struct {
	Name     string `json:"name,omitempty"`
	EPS      *int   `json:"eps,omitempty"`
	AuthType string `json:"auth_type,omitempty"`
	Status   string `json:"status,omitempty"`
}

UpdateSourceRequest represents the request to update a source

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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