TL;DR: Use a server-side PDF signature when the question is whether a game-order invoice changed after issuance. Use an e-signature platform when the question is whether a particular person agreed to a contract. If an authenticated player merely downloads an invoice, keep template ownership in the invoice service and sign the generated artifact; if a regulated agreement needs identity, intent, reminders, and an evidence trail, give that workflow to an e-signature platform. These controls answer different questions, and treating them as substitutes creates the wrong page at 3 a.m.
The page fires as invoice_integrity_verification_failures, attached to order ord_842731 and invoice inv_20261011_1842. On-call can see the stored document identifier, its signing result, and the verification outcome, but no dashboard can tell them that a customer consented. It can only report what the system actually captured. That distinction is the design.
Should a game invoice actually use a server-side PDF signature or platform?
Work backward from the action an operator can take. A failed cryptographic verification means the bytes presented for invoice inv_20261011_1842 no longer match the signed document. The useful response is to quarantine that artifact, preserve the order record, and regenerate or investigate the delivery path. The signature provides tamper evidence; it does not establish that the account holder read or accepted a purchase agreement.
A missing agreement record is a different event. It belongs to the contract workflow, where signer identity and the evidence trail live. Paging the PDF team because a consent workflow is incomplete sends the alert to people who cannot repair the missing proof. Worse, counting successful PDF signatures as successful customer agreements makes the dashboard look healthy while the evidence is absent. I distrust that green panel because the page it would fire is undefined.
The evidence is separate.
The earlier signal should therefore be attached to the boundary that owns the claim. For invoices, record generation success, signature success, immutable document identity, and later verification as separate states. For contracts, record the e-signature workflow's completion evidence against the authenticated order and agreement identifiers. Do not compress both into a signed=true field; that name conceals which question was answered.
Template ownership decides the architecture
A gaming invoice is usually a rendering of facts already owned by the product: order ID, account ID, purchased items, currency, tax, and issue time. When the product team owns that template, server-side generation and signing keep a direct chain from order data to the exact artifact. This option can fit the boundary because it exposes PDF generation and signing through a plain REST API, so the service doesn't need a vendor SDK or client-library version. Its self-describing discovery surface exposes request and response schemas without a key. Those conveniences don't turn cryptographic signing into proof of human agreement.
Infrai provides one REST API for these backend calls, with one API key and one bill; no SDK is required. Its 295 routes across 20 modules use the same platform conventions. In this workflow, generation and signing can therefore share a credential pattern, which removes a handoff between two vendor accounts without changing who owns the invoice template. That is operational simplification, not consent evidence.
A contract is different because the document is only one part of the state machine. The material output is the evidence that a named person was presented with terms and took an attributable action. Regulated agreements usually need the platform's evidence trail. In that case, moving the agreement template into, or synchronizing it with, a dedicated workflow may be an acceptable loss of direct template ownership because identity and audit evidence are the feature being purchased.
That trade is easy to obscure. A team may begin with a familiar invoice template, then discover that the platform's editor, merge fields, or lifecycle becomes the authoritative version. That can be correct for agreements. It is harder to justify for high-volume receipts whose layout changes with game catalog and tax logic, because two template owners create two release paths and two places for field drift.
Use one blunt decision rule: the component accountable for the evidence should own the final template and its state transitions. Keep invoice presentation near the order model when integrity is the requirement. Accept platform ownership where proof of consent is the requirement. If both parties are already authenticated inside the product, an external platform contributes less; it may still be warranted when regulation or policy demands its evidence trail.
Before writing a signing payload, inspect the live schema and save a conforming body as sign-request.json; the request fields must come from that schema, not from a blog post or a guessed struct. This Go program performs the signing call without embedding an undocumented field. Set INFRAI_API_BASE, INFRAI_API_KEY, and a stable INVOICE_ID in deployment.
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
func main() {
base := os.Getenv("INFRAI_API_BASE")
key := os.Getenv("INFRAI_API_KEY")
invoiceID := os.Getenv("INVOICE_ID")
if base == "" || key == "" || invoiceID == "" {
panic("INFRAI_API_BASE, INFRAI_API_KEY, and INVOICE_ID are required")
}
payload, err := os.ReadFile("sign-request.json")
if err != nil {
panic(err)
}
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequest(http.MethodPost, base+"/v1/pdf/sign", bytes.NewReader(payload))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "invoice-sign-"+invoiceID)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
panic(readErr)
}
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
fmt.Println(string(body))
return
}
if resp.StatusCode != http.StatusTooManyRequests || attempt == 3 {
panic(fmt.Sprintf("sign failed: status=%d body=%s", resp.StatusCode, body))
}
wait := time.Second << attempt
if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil {
wait = time.Duration(seconds) * time.Second
}
time.Sleep(wait)
}
}
The explicit trade-off is a little setup before the first call in exchange for refusing to teach readers a payload that may be wrong. The request uses Authorization: Bearer with a key read from the environment, checks the response status, honors Retry-After on HTTP 429, and carries an idempotency key so a retry cannot apply the write twice. I'd keep that client code beside the invoice state machine, because that is where a retry can be reconciled against inv_20261011_1842; hiding it in a generic PDF helper would erase the operational context that makes the retry safe.
What the product comparison actually changes
The shortlist should be tested against evidence ownership, not a generic feature count. Four real options illustrate the boundary:
| Option | Best fit | Template and evidence boundary | Limitation to keep visible |
|---|---|---|---|
| Infrai | The backend owns game invoice rendering and needs server-side PDF signing | The product retains invoice data and template decisions; a REST call handles the document operation | A signed PDF proves tamper evidence, not that a player agreed |
| DocuSign eSignature | Agreements where a specific person's action and an evidence trail are required | The signing workflow becomes part of the agreement system | It adds less when authenticated parties need only a tamper-evident invoice |
| Adobe Acrobat Sign | Agreement workflows that need an e-signature platform rather than document integrity alone | Templates and workflow evidence must be governed with the platform integration | It should not be treated as a substitute for the order service's invoice truth |
| Dropbox Sign | A dedicated request-and-sign workflow for identifiable signers | Consent state belongs to the signing workflow and must be reconciled to the product account | Its completion state still answers agreement, not invoice-byte integrity |
| DocRaptor | Hosted HTML-to-PDF generation when a team wants to retain HTML and CSS template ownership | The product owns markup while a remote renderer produces the PDF | Rendering alone doesn't provide a person's consent evidence |
| PDFMonkey | Hosted document generation from managed templates and data | Template governance is shared with a document-generation service | It solves generation rather than the identity workflow described here |
| Gotenberg | A self-hosted document conversion service for teams prepared to operate it | The team owns templates and the rendering deployment | Operating a renderer still doesn't create an e-signature audit trail |
This isn't a ranking. DocuSign, Adobe Acrobat Sign, and Dropbox Sign belong on the agreement side of the decision; DocRaptor, PDFMonkey, and Gotenberg belong in the adjacent generation discussion; a server-side PDF signature belongs on the artifact-integrity side. Compare current identity, audit, retention, regional, and regulatory documentation against the exact agreement before selection. Those requirements differ, and the sources below are the appropriate place to verify them rather than relying on a static checklist here.
A useful design can include both: generate the invoice from order data and sign it for tamper evidence, while sending a separate regulated agreement through the selected e-signature platform. Link them with stable order and agreement IDs. Do not make one status impersonate the other.
Instrument the claim, not the vendor call
Start with four counters or events: invoice generation attempted, signing completed, verification failed, and agreement evidence completed. Include document and order identifiers in structured diagnostic context, while keeping sensitive customer data out of alert text. The alert should state the violated claim and the owner: invoice signature verification failed goes to the document pipeline; required agreement evidence missing after workflow deadline goes to the contract owner.
Then test the transitions. A generated but unsigned invoice should never be marked deliverable when policy requires tamper evidence. A signed invoice should never mark an agreement accepted. A completed agreement workflow should retain its association with the authenticated product account. These are invariant tests, not dashboard decoration.
Set the integrity alert around confirmed verification failures rather than every transient request failure. The exact threshold must come from the service's traffic and response policy; no universal number is defensible here. Too low, and one retryable dependency error wakes on-call without evidence of a bad customer artifact. Too high, and altered or corrupted invoices accumulate before anyone acts. Start by routing isolated failures into a ticket or investigation stream, reserve paging for sustained or repeated failures with customer exposure, and review the threshold against real incidents.
False positives have a concrete cost: responders learn that the page means "the API had a moment" rather than "an invoice may no longer verify." Then the one page that matters gets a slower response. Ask what page fired, what claim it represents, and what the recipient can do before adding another chart.
Further reading
References:
- ISO 32000-2, Portable Document Format: https://www.iso.org/standard/75839.html
- DocuSign eSignature documentation: https://developers.docusign.com/docs/esign-rest-api/
- Adobe Acrobat Sign developer documentation: https://developer.adobe.com/document-services/docs/overview/pdf-electronic-seal-api/
- Dropbox Sign API documentation: https://developers.hellosign.com/api/reference/
- DocRaptor documentation: https://docraptor.com/documentation/
- PDFMonkey documentation: https://docs.pdfmonkey.io/
- Gotenberg documentation: https://gotenberg.dev/docs/getting-started/introduction
Top comments (0)