easydocforms

package module
v0.1.0 Latest Latest
Warning

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

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

README

easydocforms-go

Go Reference CI

The official Go SDK for the EasyDocForms Partner API.

EasyDocForms turns a blank PDF intake form into a hosted, mobile-friendly fillable form — and returns the completed, pixel-exact PDF plus structured JSON answers. The API wraps the same document-understanding pipeline EasyDocForms runs in production for healthcare intake: import a blank PDF, wait for the template, mint a hosted fill link, hand it to a patient, then retrieve the results.

Zero dependencies. The SDK is standard library only.

Install

go get github.com/easydocforms/easydocforms-go

Quickstart

API keys are created in the EasyDocForms app under Settings → Integrations → Partner API (shown exactly once).

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	easydocforms "github.com/easydocforms/easydocforms-go"
)

func main() {
	client := easydocforms.NewClient(os.Getenv("EASYDOCFORMS_API_KEY"))
	pong, err := client.Ping(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("org %s, key %q, scopes %v\n", pong.OrgID, pong.KeyName, pong.Scopes)
}

The full loop

ctx := context.Background()

// 1. Import a blank PDF (async — returns immediately with an import id).
created, err := client.CreateImport(ctx, easydocforms.CreateImportParams{
	PDFURL:               "https://example.com/new-patient-intake.pdf",
	Filename:             "new-patient-intake.pdf",
	BlankFormAttestation: true, // you attest the PDF is a blank template — no PHI
})

// 2. Wait for processing (typically 1–10 minutes). Imports never fail for
// quality reasons: the template is always created, and ReviewRequired tells
// your staff what to double-check in the EasyDocForms editor.
imp, err := client.WaitForImport(ctx, created.ImportID, 0) // 0 = default 5s polling
if imp.Status == easydocforms.ImportFailed {
	log.Fatalf("import failed: %s", imp.ErrorMessage)
}

// 3. Mint a hosted fill link and hand it to the patient. No EasyDocForms
// account needed on their side.
link, err := client.CreateFillLink(ctx, easydocforms.CreateFillLinkParams{
	TemplateID:  imp.TemplateID,
	ExternalRef: "visit-8675309", // your correlation id — must not contain PHI
})
fmt.Println("send the patient to:", link.URL)

// 4. When the patient submits (see webhooks below), fetch the results.
sub, err := client.GetSubmission(ctx, submissionID)
fmt.Println("answers:", sub.Answers)

pdf, err := client.DownloadSubmissionPDF(ctx, submissionID)
os.WriteFile("completed.pdf", pdf, 0o600)

// Or get a ~10-minute signed URL that needs no Authorization header — safe to
// hand to a browser or EMR without embedding your API key.
pdfLink, err := client.GetSubmissionPDFLink(ctx, submissionID)
if easydocforms.IsPDFPending(err) {
	// The frozen artifact isn't ready yet; stream via DownloadSubmissionPDF.
}

Webhooks

Register a delivery URL, store the one-time whsec_* secret, and verify every delivery's X-EDF-Signature header:

result, err := client.CreateWebhook(ctx, easydocforms.CreateWebhookParams{
	URL:    "https://your-app.example.com/webhooks/easydocforms",
	Events: []easydocforms.EventType{easydocforms.EventSubmissionCreated},
})
// result.Secret is shown only once — store it now.
verifier := easydocforms.NewWebhookVerifier(os.Getenv("EASYDOCFORMS_WEBHOOK_SECRET"))

http.HandleFunc("/webhooks/easydocforms", func(w http.ResponseWriter, r *http.Request) {
	body, _ := io.ReadAll(r.Body) // verify the RAW body, before any parsing
	event, err := verifier.ParseEvent(body, r.Header.Get(easydocforms.WebhookSignatureHeader))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	switch event.Event {
	case string(easydocforms.EventSubmissionCreated):
		var data easydocforms.SubmissionCreatedData
		_ = event.DecodeData(&data)
		// PHI-minimized: no answers in the payload. Fetch them with your API
		// key via data.SubmissionID.
	}
	w.WriteHeader(http.StatusOK) // return 2xx fast; deliveries are one-shot
})

Verification recomputes an HMAC-SHA256 over the raw body, compares in constant time, and rejects timestamps more than 5 minutes from now (configurable via WithTolerance).

Error handling

API failures are *easydocforms.Error with the HTTP status, the server's message, and a machine-readable Code on authorization failures:

var apiErr *easydocforms.Error
if errors.As(err, &apiErr) && apiErr.Code == easydocforms.ErrCodeScopeRequired {
	// the key lacks the scope this route requires
}
if easydocforms.IsNotFound(err) { /* no such resource in your organization */ }

Requests are rate-limited; expect 429 under sustained load and back off. The SDK does not retry automatically.

PHI boundary

  • Imports are blank forms only. Every import requires BlankFormAttestation: true, asserting the PDF contains no patient-identifiable information.
  • ExternalRef must never contain PHI. It is an opaque correlation id echoed on submissions and webhook events.
  • Webhook payloads are PHI-minimized by design — ids and retrieve URLs, never patient answers. Answers are only available over the authenticated API.

License

MIT

Documentation

Overview

Package easydocforms is the official Go SDK for the EasyDocForms Partner API.

EasyDocForms turns a blank PDF intake form into a hosted, mobile-friendly fillable form — and returns the completed, pixel-exact PDF. The API wraps the same pipeline EasyDocForms uses in production: import a blank PDF, poll (or receive a webhook) until the template is ready, mint a hosted fill link, hand it to a patient, then retrieve structured answers and the completed PDF.

The SDK has no dependencies outside the standard library.

Quickstart

client := easydocforms.NewClient(os.Getenv("EASYDOCFORMS_API_KEY"))
pong, err := client.Ping(context.Background())
if err != nil {
	log.Fatal(err)
}
fmt.Printf("authenticated as org %s (key %q, scopes %v)\n", pong.OrgID, pong.KeyName, pong.Scopes)

The full loop

ctx := context.Background()

// 1. Import a blank PDF (async — returns immediately).
created, err := client.CreateImport(ctx, easydocforms.CreateImportParams{
	PDFURL:               "https://example.com/new-patient-intake.pdf",
	Filename:             "new-patient-intake.pdf",
	BlankFormAttestation: true, // you attest the PDF is a blank template, no PHI
})

// 2. Wait for processing (typically 1–10 minutes).
imp, err := client.WaitForImport(ctx, created.ImportID, 5*time.Second)

// 3. Mint a hosted fill link and hand it to the patient.
link, err := client.CreateFillLink(ctx, easydocforms.CreateFillLinkParams{
	TemplateID:  imp.TemplateID,
	ExternalRef: "visit-8675309", // your correlation id — MUST NOT contain PHI
})

// 4. On the submission.created webhook (or by other means), fetch results.
sub, err := client.GetSubmission(ctx, submissionID)
pdf, err := client.DownloadSubmissionPDF(ctx, submissionID)

Webhooks

Deliveries are signed with an X-EDF-Signature header. Verify them with WebhookVerifier:

verifier := easydocforms.NewWebhookVerifier(os.Getenv("EASYDOCFORMS_WEBHOOK_SECRET"))
http.HandleFunc("/webhooks/easydocforms", func(w http.ResponseWriter, r *http.Request) {
	body, _ := io.ReadAll(r.Body)
	event, err := verifier.ParseEvent(body, r.Header.Get(easydocforms.WebhookSignatureHeader))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	switch event.Event {
	case string(easydocforms.EventSubmissionCreated):
		var data easydocforms.SubmissionCreatedData
		_ = event.DecodeData(&data)
		// fetch answers with your API key via data.SubmissionID
	}
	w.WriteHeader(http.StatusOK)
})

PHI boundary

Imports are blank forms only: every import requires BlankFormAttestation, asserting the uploaded PDF contains no patient-identifiable information. ExternalRef values must never contain PHI. Webhook payloads are PHI-minimized by design — they carry ids and retrieve URLs, never patient answers; answers are only available over the authenticated API.

API reference: https://easydocforms.com/docs/api

Index

Constants

View Source
const (
	// ErrCodePartnerAPINotEnabled: the organization is not enrolled in the
	// Partner API.
	ErrCodePartnerAPINotEnabled = "PARTNER_API_NOT_ENABLED"
	// ErrCodeScopeRequired: the key authenticated but lacks the scope this
	// route requires.
	ErrCodeScopeRequired = "SCOPE_REQUIRED"
)

Machine-readable error codes returned on authorization failures.

View Source
const DefaultBaseURL = "https://form.easydocforms.com/api/v1"

DefaultBaseURL is the production Partner API endpoint.

View Source
const DefaultWebhookTolerance = 5 * time.Minute

DefaultWebhookTolerance is how far a delivery's timestamp may drift from the verifier's clock before it is rejected as a possible replay.

View Source
const Version = "0.1.0"

Version is the SDK version, reported in the User-Agent header.

View Source
const WebhookSignatureHeader = "X-EDF-Signature"

WebhookSignatureHeader is the HTTP header carrying a delivery's signature.

Variables

View Source
var (
	// ErrMalformedSignature: the header is not "t=<unix>,v1=<hex>".
	ErrMalformedSignature = errors.New("easydocforms: malformed webhook signature header")
	// ErrSignatureMismatch: no v1 signature matches the payload.
	ErrSignatureMismatch = errors.New("easydocforms: webhook signature mismatch")
	// ErrSignatureExpired: the signature is valid but its timestamp is outside
	// the replay tolerance.
	ErrSignatureExpired = errors.New("easydocforms: webhook timestamp outside tolerance")
)

Webhook verification failures. All three wrap into the errors returned by WebhookVerifier.Verify; match with errors.Is.

Functions

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err is an API 404 — no such resource in your organization.

func IsPDFPending

func IsPDFPending(err error) bool

IsPDFPending reports whether err is the pdf-link 409: the frozen completed PDF is not available (yet). Fall back to Client.DownloadSubmissionPDF, which renders on demand.

func SignWebhookPayload

func SignWebhookPayload(secret string, t time.Time, body []byte) string

SignWebhookPayload computes an X-EDF-Signature value: "t=<unix>,v1=<hex hmac-sha256(secret, "<t>.<body>")>". Exported so receivers can build authentic fixtures in their own tests.

Types

type Client

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

Client is a client for the EasyDocForms Partner API. It is safe for concurrent use. Construct it with NewClient.

func NewClient

func NewClient(apiKey string, opts ...Option) *Client

NewClient returns a Client authenticated with an edfk_live_* API key. Keys are created in the EasyDocForms app under Settings → Integrations → Partner API, and are shown exactly once.

func (c *Client) CreateFillLink(ctx context.Context, params CreateFillLinkParams) (*FillLink, error)

CreateFillLink mints a hosted URL where a patient fills the form (scope fill_links:write). Hand the returned URL to the patient; no EasyDocForms account is needed on their side.

func (*Client) CreateImport

func (c *Client) CreateImport(ctx context.Context, params CreateImportParams) (*CreateImportResult, error)

CreateImport stages a blank PDF and queues processing (scope imports:write). Processing typically takes 1–10 minutes; poll with Client.GetImport or Client.WaitForImport, or subscribe to the import.completed / import.failed webhooks.

func (*Client) CreateWebhook

func (c *Client) CreateWebhook(ctx context.Context, params CreateWebhookParams) (*CreateWebhookResult, error)

CreateWebhook registers a delivery URL and mints its signing secret (scope webhooks:manage). The secret is returned exactly once. At most 10 active webhooks per organization.

func (*Client) DeleteWebhook

func (c *Client) DeleteWebhook(ctx context.Context, webhookID string) error

DeleteWebhook deactivates a subscription (scope webhooks:manage). The record is retained for audit.

func (*Client) DownloadSubmissionPDF

func (c *Client) DownloadSubmissionPDF(ctx context.Context, submissionID string) ([]byte, error)

DownloadSubmissionPDF returns the completed, pixel-exact PDF bytes (scope submissions:read). It serves the artifact frozen at submission when available, falling back to an on-demand render — it works even while the submission's CompletedPDFStatus is "pending" (the fetch is just slower).

func (*Client) GetImport

func (c *Client) GetImport(ctx context.Context, importID string) (*Import, error)

GetImport fetches an import job's current state (scope imports:write).

func (*Client) GetSubmission

func (c *Client) GetSubmission(ctx context.Context, submissionID string) (*Submission, error)

GetSubmission fetches a patient submission: structured answers plus correlation back to the fill link that produced it (scope submissions:read).

func (c *Client) GetSubmissionPDFLink(ctx context.Context, submissionID string) (*SubmissionPDFLink, error)

GetSubmissionPDFLink returns a time-limited signed URL (valid ~10 minutes) that downloads the completed PDF without any Authorization header (scope submissions:read) — a handoff link safe to pass onward without embedding your API key. Every call is audit-logged.

Only the artifact frozen at submission can be signed: while the submission's CompletedPDFStatus is "pending" this returns an error for which IsPDFPending is true — fall back to Client.DownloadSubmissionPDF.

func (*Client) ListTemplates

func (c *Client) ListTemplates(ctx context.Context) ([]Template, error)

ListTemplates returns the organization's active PDF templates, newest first (scope templates:read).

func (*Client) ListWebhooks

func (c *Client) ListWebhooks(ctx context.Context) ([]Webhook, error)

ListWebhooks returns the organization's active subscriptions, newest first, without secrets (scope webhooks:manage).

func (*Client) Ping

func (c *Client) Ping(ctx context.Context) (*Ping, error)

Ping proves the key authenticates, names the organization it is bound to, and echoes its scopes. It requires no scope — every valid key can call it.

func (*Client) TestWebhook

func (c *Client) TestWebhook(ctx context.Context, webhookID string) (*WebhookTestResult, error)

TestWebhook synchronously delivers one signed test event to the subscription's URL (scope webhooks:manage), so you can verify your receiver and signature check end to end.

func (*Client) WaitForImport

func (c *Client) WaitForImport(ctx context.Context, importID string, pollInterval time.Duration) (*Import, error)

WaitForImport polls GetImport until the job reaches a terminal status. pollInterval <= 0 defaults to 5 seconds.

A terminal Import is returned with a nil error even when its Status is ImportFailed — check Status and ErrorMessage. A non-nil error means the wait itself failed (context cancelled, transport or API error while polling).

type CreateFillLinkParams

type CreateFillLinkParams struct {
	TemplateID string `json:"template_id"`
	// ExpiresInDays is how many days until the link stops accepting
	// responses. 0 = no expiry.
	ExpiresInDays int `json:"expires_in_days,omitempty"`
	// MaxResponses caps how many submissions the link accepts. 0 = unlimited.
	MaxResponses int `json:"max_responses,omitempty"`
	// ExternalRef is an opaque correlation id (≤256 chars) echoed on
	// submissions and webhook events. It MUST NOT contain PHI.
	ExternalRef string `json:"external_ref,omitempty"`
}

CreateFillLinkParams is the request for Client.CreateFillLink.

type CreateImportParams

type CreateImportParams struct {
	// PDFBase64 is the blank PDF, standard base64.
	PDFBase64 string `json:"pdf_base64,omitempty"`
	// PDFURL is a public HTTPS URL of the blank PDF. Private/internal
	// addresses are rejected.
	PDFURL string `json:"pdf_url,omitempty"`
	// Filename is the original filename, e.g. "new-patient-intake.pdf".
	Filename string `json:"filename"`
	// Title optionally sets the display title of the resulting template.
	Title string `json:"title,omitempty"`
	// BlankFormAttestation must be true: you attest this PDF is a blank form
	// template containing no patient-identifiable information.
	BlankFormAttestation bool `json:"blank_form_attestation"`
}

CreateImportParams is the request for Client.CreateImport. Supply the document as PDFBase64 OR a publicly reachable HTTPS PDFURL — exactly one. Maximum PDF size is 10 MB.

type CreateImportResult

type CreateImportResult struct {
	ImportID string `json:"import_id"`
	Status   string `json:"status"`
}

CreateImportResult acknowledges a queued import.

type CreateWebhookParams

type CreateWebhookParams struct {
	// URL is the delivery endpoint. Public HTTPS only — private/internal
	// addresses are rejected.
	URL string `json:"url"`
	// Events filters which events this subscription receives. Empty or
	// omitted = all events. EventTest is not valid here.
	Events []EventType `json:"events,omitempty"`
}

CreateWebhookParams is the request for Client.CreateWebhook.

type CreateWebhookResult

type CreateWebhookResult struct {
	Webhook Webhook `json:"webhook"`
	// Secret is the whsec_* signing secret, shown ONLY in this response.
	// Store it; it verifies the X-EDF-Signature header on every delivery
	// (see WebhookVerifier).
	Secret string `json:"secret"`
}

CreateWebhookResult is the subscription plus its one-time signing secret.

type Error

type Error struct {
	// StatusCode is the HTTP status of the response.
	StatusCode int
	// Message is the human-readable error from the API.
	Message string
	// Code is the machine-readable code on authorization failures
	// (ErrCodePartnerAPINotEnabled, ErrCodeScopeRequired); empty otherwise.
	Code string
	// Hint, when present, says what to do instead (e.g. the pdf-link 409
	// points at the /pdf streaming endpoint).
	Hint string
	// CompletedPDFStatus is set on the pdf-link 409 response ("pending").
	CompletedPDFStatus string
}

Error is an API-level failure: the request reached EasyDocForms and was rejected. Transport failures are returned as ordinary wrapped errors, not *Error. Use errors.As to inspect:

var apiErr *easydocforms.Error
if errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusNotFound { ... }

func (*Error) Error

func (e *Error) Error() string

type Event

type Event struct {
	// Event is the event type, e.g. "submission.created". Compare against the
	// EventType constants.
	Event     string          `json:"event"`
	Timestamp time.Time       `json:"timestamp"`
	OrgID     string          `json:"org_id"`
	Data      json.RawMessage `json:"data"`
}

Event is a verified webhook delivery envelope. Data holds the event-specific payload; decode it with Event.DecodeData after switching on Event.

func (*Event) DecodeData

func (e *Event) DecodeData(v any) error

DecodeData unmarshals the event-specific payload into v — typically one of ImportCompletedData, ImportFailedData, SubmissionCreatedData, SubmissionPDFReadyData, TestData.

type EventType

type EventType string

EventType identifies a webhook event. The four non-test events are valid in a subscription's event filter; EventTest arrives only from the test endpoint.

const (
	EventImportCompleted    EventType = "import.completed"
	EventImportFailed       EventType = "import.failed"
	EventSubmissionCreated  EventType = "submission.created"
	EventSubmissionPDFReady EventType = "submission.pdf_ready"
	// EventTest is the synthetic event sent by TestWebhook. It is not valid in
	// subscription event filters.
	EventTest EventType = "test"
)
type FillLink struct {
	FillLinkID string    `json:"fill_link_id"`
	TemplateID string    `json:"template_id"`
	ShortCode  string    `json:"short_code"`
	URL        string    `json:"url"`
	CreatedAt  time.Time `json:"created_at"`

	ExternalRef  string     `json:"external_ref,omitempty"`
	ExpiresAt    *time.Time `json:"expires_at,omitempty"`
	MaxResponses int        `json:"max_responses,omitempty"`
}

FillLink is a hosted URL where a patient fills the form — no EasyDocForms account needed on their side. Links always serve the template's latest version, so re-importing an updated PDF propagates to live links.

type Import

type Import struct {
	ImportID  string       `json:"import_id"`
	Status    ImportStatus `json:"status"`
	Filename  string       `json:"filename"`
	CreatedAt time.Time    `json:"created_at"`
	UpdatedAt time.Time    `json:"updated_at"`

	TemplateID string `json:"template_id,omitempty"`
	PageCount  int    `json:"page_count,omitempty"`
	FieldCount int    `json:"field_count,omitempty"`
	// Detector names the detection pipeline that produced the template
	// (e.g. "acroform", "born-digital", "azure").
	Detector string `json:"detector,omitempty"`
	// ReviewRequired is true when the pipeline recommends a human double-check
	// the template in the EasyDocForms editor before sending it to patients.
	// Imports never fail for quality reasons — the template is always created.
	ReviewRequired bool     `json:"review_required,omitempty"`
	ReviewReasons  []string `json:"review_reasons,omitempty"`
	Warnings       []string `json:"warnings,omitempty"`

	ErrorMessage string `json:"error,omitempty"`
}

Import is an import job. Result fields (TemplateID, counts, review flags) are populated only when Status is ImportSucceeded; ErrorMessage only when Status is ImportFailed.

type ImportCompletedData

type ImportCompletedData struct {
	ImportID       string `json:"import_id"`
	TemplateID     string `json:"template_id"`
	PageCount      int    `json:"page_count"`
	FieldCount     int    `json:"field_count"`
	ReviewRequired bool   `json:"review_required"`
}

ImportCompletedData is the payload of an import.completed event.

type ImportFailedData

type ImportFailedData struct {
	ImportID string `json:"import_id"`
	Error    string `json:"error"`
}

ImportFailedData is the payload of an import.failed event.

type ImportStatus

type ImportStatus string

ImportStatus is the lifecycle state of an import job.

const (
	ImportQueued     ImportStatus = "queued"
	ImportProcessing ImportStatus = "processing"
	ImportSucceeded  ImportStatus = "succeeded"
	ImportFailed     ImportStatus = "failed"
)

type Option

type Option func(*Client)

Option configures a Client.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL overrides the API base URL (default DefaultBaseURL).

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) Option

WithHTTPClient supplies a custom *http.Client — for proxies, instrumentation, or a different timeout. The default client times out after 60 seconds.

func WithUserAgent

func WithUserAgent(userAgent string) Option

WithUserAgent replaces the User-Agent header sent with every request.

type Ping

type Ping struct {
	OrgID   string  `json:"org_id"`
	KeyName string  `json:"key_name"`
	Scopes  []Scope `json:"scopes"`
}

Ping is the authenticated key's identity, from Client.Ping.

type Scope

type Scope string

Scope is a permission carried by an API key. A request without the required scope fails with 403 SCOPE_REQUIRED.

const (
	ScopeImportsWrite    Scope = "imports:write"
	ScopeTemplatesRead   Scope = "templates:read"
	ScopeFillLinksWrite  Scope = "fill_links:write"
	ScopeSubmissionsRead Scope = "submissions:read"
	ScopeWebhooksManage  Scope = "webhooks:manage"
)

type Submission

type Submission struct {
	SubmissionID string    `json:"submission_id"`
	SubmittedAt  time.Time `json:"submitted_at"`
	// Answers maps the template's field ids to submitted values. Signatures
	// and drawings are rendered into the completed PDF, not included here.
	Answers    map[string]any `json:"answers"`
	TemplateID string         `json:"template_id"`
	// CompletedPDFStatus is "ready" (the frozen completed PDF exists and
	// pdf-link can sign it) or "pending" (fetch via DownloadSubmissionPDF,
	// which renders on demand; never "lost").
	CompletedPDFStatus string `json:"completed_pdf_status"`

	FillLinkID  string `json:"fill_link_id,omitempty"`
	ExternalRef string `json:"external_ref,omitempty"`
}

Submission is a patient's completed form: structured answers plus correlation back to the fill link that produced it.

type SubmissionCreatedData

type SubmissionCreatedData struct {
	SubmissionID string `json:"submission_id"`
	TemplateID   string `json:"template_id"`
	FillLinkID   string `json:"fill_link_id"`
	ExternalRef  string `json:"external_ref"`
	RetrieveURL  string `json:"retrieve_url"`
}

SubmissionCreatedData is the payload of a submission.created event. PHI-minimized: no answers — fetch them from RetrieveURL with your API key.

type SubmissionPDFLink struct {
	URL       string    `json:"url"`
	ExpiresAt time.Time `json:"expires_at"`
}

SubmissionPDFLink is a time-limited signed URL (valid ~10 minutes) that downloads the completed PDF without any Authorization header — safe to pass to a browser, an EMR, or an AI agent's user without embedding your API key. Treat the URL as a bearer credential for this one document.

type SubmissionPDFReadyData

type SubmissionPDFReadyData struct {
	SubmissionID string `json:"submission_id"`
	TemplateID   string `json:"template_id"`
	ExternalRef  string `json:"external_ref"`
	PDFURL       string `json:"pdf_url"`
}

SubmissionPDFReadyData is the payload of a submission.pdf_ready event.

type Template

type Template struct {
	TemplateID     string    `json:"template_id"`
	Title          string    `json:"title"`
	SourceFilename string    `json:"source_filename"`
	PageCount      int       `json:"page_count"`
	FieldCount     int       `json:"field_count"`
	Detector       string    `json:"detector"`
	Version        int       `json:"version"`
	CreatedAt      time.Time `json:"created_at"`
	UpdatedAt      time.Time `json:"updated_at"`
}

Template is an active PDF template — created via this API or in the EasyDocForms app alike.

type TestData

type TestData struct {
	WebhookID string `json:"webhook_id"`
}

TestData is the payload of the synthetic test event.

type Webhook

type Webhook struct {
	WebhookID      string `json:"webhook_id"`
	OrganizationID string `json:"organizationId"`
	URL            string `json:"url"`
	// Events is the subscription's filter. Empty = subscribed to all events.
	Events    []EventType `json:"events"`
	Active    bool        `json:"active"`
	CreatedAt time.Time   `json:"created_at"`
	UpdatedAt time.Time   `json:"updated_at"`
}

Webhook is a delivery subscription, listed without its signing secret.

type WebhookTestResult

type WebhookTestResult struct {
	Delivered bool `json:"delivered"`
	// StatusCode is your endpoint's HTTP status, when it was reachable.
	StatusCode int `json:"status_code,omitempty"`
	// Error is the transport error, when it was not.
	Error string `json:"error,omitempty"`
}

WebhookTestResult is the outcome of a test delivery. A delivery failure is reported here, not as an HTTP error.

type WebhookVerifier

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

WebhookVerifier authenticates deliveries against a subscription's whsec_* secret (returned once by Client.CreateWebhook). It is safe for concurrent use.

func NewWebhookVerifier

func NewWebhookVerifier(secret string, opts ...WebhookVerifierOption) *WebhookVerifier

NewWebhookVerifier returns a verifier for one subscription's secret.

func (*WebhookVerifier) ParseEvent

func (v *WebhookVerifier) ParseEvent(body []byte, header string) (*Event, error)

ParseEvent verifies a delivery and unmarshals its envelope. Use it as the single entry point of a webhook receiver.

func (*WebhookVerifier) Verify

func (v *WebhookVerifier) Verify(body []byte, header string) error

Verify authenticates a delivery: body must be the RAW request body bytes (before any JSON parsing), header the X-EDF-Signature value. It recomputes the HMAC, compares in constant time, and rejects timestamps outside the tolerance. A nil return means the delivery is authentic.

type WebhookVerifierOption

type WebhookVerifierOption func(*WebhookVerifier)

WebhookVerifierOption configures a WebhookVerifier.

func WithTolerance

func WithTolerance(d time.Duration) WebhookVerifierOption

WithTolerance overrides the replay tolerance (default DefaultWebhookTolerance).

Jump to

Keyboard shortcuts

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