Documentation
¶
Overview ¶
Package nexra is the Go SDK for the Nexra platform API.
Every operation in the API is generated from its OpenAPI document into the nexraapi package. This package adds what the generator does not: client construction from a token and workspace, retries with backoff, typed errors, cursor pages, safe run starts and webhook signature checks.
client, err := nexra.NewClient(nexra.Options{}) // NEXRA_TOKEN and NEXRA_WORKSPACE_ID
integrations, _, err := client.IntegrationsAPI.ListIntegrations(ctx).Execute()
Index ¶
- Constants
- Variables
- func BackoffDelay(attempt int, options RetryOptions, random func() float64) time.Duration
- func Collect[T any](items iter.Seq2[T, error], limit int) ([]T, error)
- func NewIdempotencyKey(prefix string) string
- func Paginate[T any](ctx context.Context, ...) iter.Seq2[T, error]
- func ParseError(response *http.Response, err error) error
- func RetryAfter(value string, now time.Time) (time.Duration, bool)
- func SignTriggerRequest(rawBody []byte, secret, eventID string, timestamp time.Time) (map[string]string, error)
- func SignWebhookPayload(rawBody []byte, secret string, timestamp time.Time) string
- func VerifyWebhookSignature(rawBody []byte, header, secret string, options VerifyOptions) bool
- type APIError
- type Client
- type Event
- type Options
- type Page
- type RetryOptions
- type RetryTransport
- type StartRunOptions
- type VerifyOptions
Examples ¶
Constants ¶
const APIVersion = "2026-10-01"
APIVersion is the dated version of the Nexra API this SDK was built from.
const DefaultBaseURL = "https://api.nexra.amakoragroup.com"
DefaultBaseURL is the Nexra API.
const DefaultTolerance = 5 * time.Minute
DefaultTolerance is the oldest signature timestamp accepted.
const SignatureHeader = "X-Amakora-Signature"
SignatureHeader carries Nexra's signature on event deliveries.
const Version = "1.0.0"
Version is this SDK's version.
Variables ¶
var ( ErrBadRequest = errors.New("nexra: bad request") // 400, 422 ErrAuthentication = errors.New("nexra: not signed in") // 401 ErrPermission = errors.New("nexra: not allowed") // 403 ErrNotFound = errors.New("nexra: not found") // 404 ErrConflict = errors.New("nexra: conflict") // 409 ErrRateLimited = errors.New("nexra: too many requests") // 429 ErrServer = errors.New("nexra: server error") // 5xx )
Kinds of refusal. Test for them with errors.Is:
if errors.Is(err, nexra.ErrNotFound) { ... }
var DefaultRetryOptions = RetryOptions{MaxRetries: 3, BaseDelay: 500 * time.Millisecond, MaxDelay: 20 * time.Second}
DefaultRetryOptions are 3 retries from 500ms, capped at 20s.
var ErrNoToken = errors.New("nexra: an access token is needed: set Options.Token or NEXRA_TOKEN")
ErrNoToken is returned by NewClient when no token is given or set.
var ErrWebhookVerification = errors.New("nexra: the signature is missing, does not match, or is older than the tolerance")
ErrWebhookVerification means the signature is missing, wrong or too old.
Functions ¶
func BackoffDelay ¶
func BackoffDelay(attempt int, options RetryOptions, random func() float64) time.Duration
BackoffDelay is the wait before retry attempt (1-based): the upper half of an exponential ceiling, with jitter. random returns a number in [0, 1).
func NewIdempotencyKey ¶
NewIdempotencyKey is the prefix and 32 random hex characters.
func Paginate ¶
func Paginate[T any](ctx context.Context, fetch func(ctx context.Context, cursor string) (Page[T], error)) iter.Seq2[T, error]
Paginate follows cursors until the last page. fetch receives the cursor ("" for the first page). Most Nexra lists return a capped array and need no paging; governance lists return items and nextCursor.
pages := nexra.Paginate(ctx, func(ctx context.Context, cursor string) (nexra.Page[nexraapi.EvidenceEntry], error) {
request := client.GovernanceAPI.ListEvidence(ctx)
if cursor != "" {
request = request.Cursor(cursor)
}
page, response, err := request.Execute()
if err != nil {
return nexra.Page[nexraapi.EvidenceEntry]{}, nexra.ParseError(response, err)
}
return nexra.Page[nexraapi.EvidenceEntry]{Items: page.Items, NextCursor: page.GetNextCursor()}, nil
})
for entry, err := range pages { ... }
Example ¶
package main
import (
"context"
"fmt"
"log"
nexra "github.com/TochukwuAchebe/nexra-go"
"github.com/TochukwuAchebe/nexra-go/nexraapi"
)
func main() {
ctx := context.Background()
client, _ := nexra.NewClient(nexra.Options{})
entries := nexra.Paginate(ctx, func(ctx context.Context, cursor string) (nexra.Page[nexraapi.EvidenceEntry], error) {
request := client.GovernanceAPI.ListEvidence(ctx)
if cursor != "" {
request = request.Cursor(cursor)
}
page, response, err := request.Execute()
if err != nil {
return nexra.Page[nexraapi.EvidenceEntry]{}, nexra.ParseError(response, err)
}
return nexra.Page[nexraapi.EvidenceEntry]{Items: page.Items, NextCursor: page.GetNextCursor()}, nil
})
for entry, err := range entries {
if err != nil {
log.Fatal(err)
}
fmt.Println(entry.GetSequence(), entry.GetEventType())
}
}
Output:
func ParseError ¶
ParseError turns the error from a generated Execute() call into an *APIError when Nexra answered with a refusal. Other errors (network, context, decoding) are returned unchanged, and nil stays nil.
flow, response, err := client.FlowsAPI.GetFlow(ctx, id).Execute()
if err := nexra.ParseError(response, err); errors.Is(err, nexra.ErrNotFound) { ... }
func RetryAfter ¶
RetryAfter parses a Retry-After value (seconds or an HTTP date). The second result is false when the value is missing or not valid.
func SignTriggerRequest ¶
func SignTriggerRequest(rawBody []byte, secret, eventID string, timestamp time.Time) (map[string]string, error)
SignTriggerRequest returns the headers for a signed request to a Nexra webhook trigger (POST /api/connect/triggers/{publicId}). The signed bytes are "v1:<timestamp>:<eventID>:<raw body>". eventID must be unique per delivery: 8 to 128 of A-Z a-z 0-9 . _ : -
func SignWebhookPayload ¶
SignWebhookPayload signs a body the way Nexra does. Useful for testing your handler.
func VerifyWebhookSignature ¶
func VerifyWebhookSignature(rawBody []byte, header, secret string, options VerifyOptions) bool
VerifyWebhookSignature reports whether header is a valid, fresh signature of rawBody with secret. Nexra signs "<t>.<raw body>" with HMAC-SHA256 and sends "t=<unix seconds>,v1=<hex>". Verify the raw bytes before parsing them.
Types ¶
type APIError ¶
type APIError struct {
Status int
Message string
Code string
RequestID string
// RetryAfter is the Retry-After header, for 429 answers.
RetryAfter string
Body []byte
}
APIError is a refusal from Nexra, with its status, message, stable code (where one exists) and request id. Quote RequestID when you contact support.
func NewAPIError ¶
NewAPIError builds an APIError from a status, headers and body in Nexra's error shape (other bodies are kept as text).
type Client ¶
type Client struct {
*nexraapi.APIClient
// BaseURL is the API address the client calls.
BaseURL string
}
Client is the generated API client with the SDK's auth and retries installed. Use its service fields, for example client.RunsAPI.
func NewClient ¶
NewClient makes a client for the Nexra API.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"log"
nexra "github.com/TochukwuAchebe/nexra-go"
)
func main() {
ctx := context.Background()
client, err := nexra.NewClient(nexra.Options{}) // NEXRA_TOKEN and NEXRA_WORKSPACE_ID
if err != nil {
log.Fatal(err)
}
integrations, response, err := client.IntegrationsAPI.ListIntegrations(ctx).Execute()
if err != nil {
log.Fatal(nexra.ParseError(response, err))
}
for _, integration := range integrations {
fmt.Println(integration.GetName(), integration.GetStatus())
}
_, response, err = client.FlowsAPI.GetFlow(ctx, "cmflow01orders").Execute()
if err := nexra.ParseError(response, err); errors.Is(err, nexra.ErrNotFound) {
fmt.Println("No such flow")
}
}
Output:
type Event ¶
type Event struct {
ID string `json:"id"`
Type string `json:"type"`
Version string `json:"version"`
CreatedAt time.Time `json:"createdAt"`
Mode string `json:"mode"`
WorkspaceID string `json:"workspaceId"`
Data json.RawMessage `json:"data"`
}
Event is a Nexra event envelope. Data holds the event's own fields; decode it into the matching nexraapi.Event* model when you need them typed.
func ConstructEvent ¶
func ConstructEvent(rawBody []byte, header, secret string, options VerifyOptions) (*Event, error)
ConstructEvent verifies the signature and returns the parsed event, or an error that matches ErrWebhookVerification.
type Options ¶
type Options struct {
// Token is a Nexra access token (sent as Authorization: Bearer).
// Defaults to the NEXRA_TOKEN environment variable.
Token string
// TokenSource returns a current token for each request, for tokens you
// refresh yourself. It takes precedence over Token.
TokenSource func() (string, error)
// WorkspaceID is the workspace to act in (X-Workspace-Id).
// Defaults to NEXRA_WORKSPACE_ID.
WorkspaceID string
// BaseURL defaults to NEXRA_API_URL, then DefaultBaseURL.
BaseURL string
// Retry sets backoff. Nil uses DefaultRetryOptions.
Retry *RetryOptions
// DisableRetries turns retries off.
DisableRetries bool
// HTTPClient is used for requests. Its Transport is wrapped with auth
// and retries. Defaults to a client with a 30 second timeout.
HTTPClient *http.Client
// Headers are added to every request.
Headers map[string]string
}
Options configure a Client. Every field is optional.
type RetryOptions ¶
type RetryOptions struct {
// MaxRetries after the first attempt. 0 turns retries off.
MaxRetries int
// BaseDelay is the first backoff.
BaseDelay time.Duration
// MaxDelay caps a single wait.
MaxDelay time.Duration
}
RetryOptions set how failed requests are retried.
A request is retried when the network fails or the answer is 408, 425, 429, 500, 502, 503 or 504. To keep retries safe, a request that changes data (POST or PATCH) is only retried when Nexra did not act on it (429) or when its JSON body carries an idempotencyKey, which makes a repeat return the first result. Retry-After is honoured.
type RetryTransport ¶
type RetryTransport struct {
Base http.RoundTripper
Options RetryOptions
// Sleep waits between attempts. Defaults to a timer that stops when the
// request's context ends.
Sleep func(request *http.Request, wait time.Duration) error
}
RetryTransport is an http.RoundTripper that applies Nexra's retry rules.
type StartRunOptions ¶
type StartRunOptions struct {
// IdempotencyKey defaults to a fresh key, so a retry never starts a second run.
IdempotencyKey string
// CorrelationID defaults to a fresh id.
CorrelationID string
TriggerReference string
InputID string
EndUserID string
ExternalUserID string
}
StartRunOptions are the optional fields of a run start.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
quickstart
command
Lists integrations and, given a flow id, starts a sandbox run and reads it back.
|
Lists integrations and, given a flow id, starts a sandbox run and reads it back. |
|
webhook-receiver
command
Receives Nexra events on :8080/nexra/events and verifies each signature.
|
Receives Nexra events on :8080/nexra/events and verifies each signature. |