Octopus (OCTO_ESIM) — federated eSIM
eSIM vendor adapter consuming another Octopus's /api/v1/esim — login-token auth, the airtight delivered=PROCESSING webhook rule, two-factor webhook security.
Quick facts
Code OCTO_ESIM · Line eSIM · Auth login-token (octopuscommon.TokenManager) · Model async — webhook is only a "poll now" nudge · Webhook HMAC + URL path token · Delivery activation_code + ICCID (from GET only) · Adapter services/external_vendors/esim/octopus/
The eSIM member of the OCTO federation family — consumes another Octopus's /api/v1/esim. Registered esim/factory.go:152. Default timeout 90s (matches DT One eSIM). Uses shared octopuscommon TokenManager + SelfLoopGuard. See the self-vendor memory.
Auth
Shared octopuscommon.NewTokenManager + bearerAuth. Credentials: host (→ APIBaseURL, falls back to Credentials["host"]), username, password, webhook_secret, self_base_url.
Catalog
GetOperators = GET /api/v1/esim/products; GetPlans = GET /api/v1/esim/products/{id}/variants (bare array or {"data":[...]}). Composite Plan.ID = "productID:variantID". ShouldSyncPlans()=false (provisioned directly).
Order create
PurchaseEsim → POST /api/v1/esim/orders {product_id, amount, client_reference} (composite PlanID → upstreamProductID() prefix; MerchantOrderID → client_reference). 2xx → parse; unparseable success → leave status empty (PENDING); 400+duplicate → ErrDuplicateMerchantRef; transient (408/429/5xx) → PENDING; other 4xx → terminal FAILED.
Order status — the authoritative completion path
GetOrderStatus — by id GET /api/v1/esim/orders/{id}, or recovery by ?client_reference=. This GET returns activation_code; the webhook never does.
Webhook — the eSIM airtight rule (headline)
Status is derived from the event TYPE, not data.status:
esim.delivered→ PROCESSING — a non-terminal "poll now" nudge. The webhook omitsactivation_code, so it cannot complete the order;ProcessEsimWebhookreduces PROCESSING to PENDING (a terminal short-circuit guards against regression), and the cron poll'sGetOrderStatusfetches the code and completes it.esim.failed → FAILED(terminal, triggers auto-refund);esim.cancelled → CANCELLED.esim.installed/activated/depleted/unknown → rejected (ok=false) so lifecycle events can't regress an order.
This omission is intentional and mirrored by the upstream TriggerEsimEvent, which deliberately leaves activation_code out of the webhook data.
Two-factor webhook security
VerifyWebhookSignature (HMAC; blank ⇒ true) plus an unguessable URL path token — the handler reads webhook_path_token and constant-time compares, 401 on blank/mismatch. The signature is defence-in-depth.
Delivery
ActivationCode + ICCID are carried back — but only populated on a delivered GET, never from the webhook. LookupCreditPartyStatus is a graceful no-op (Success=false, nil err) so the lifecycle poller finds nothing and moves on.
Quirks
Composite PlanID; bare-array lists; write-only client_reference; delivered=PROCESSING nudge → cron poll completes; lifecycle events rejected; ShouldSyncPlans=false; two-factor webhook.
Tests
esim/octopus/octopus_esim_vendor_test.go, octopus_esim_fuzz_test.go, octopus_esim_soak_test.go (goleak + -race), octopus_esim_sandbox_test.go. E2E: test/clientapi/octopus_esim_orchestration_test.go (build tag orchestration, incl. bad path-token). Uses test/octopusfake/ — its eSIM engine renders activation_code/iccid only on a delivered GET, mirroring "webhook never carries the code." Webhook-body gotcha: use testhelpers.WithRawBody.
DT One eSIM
eSIM vendor adapter — DT One DVS service_id 13, async PIN purchase, activation_code/ICCID delivery, URL-path-token webhook auth, install/activation polling.
Client API Reference (/api/v1)
The machine-facing REST API clients integrate against — every /api/v1 endpoint, request/response contracts, the two pagination conventions, the error envelope, idempotency semantics, and the async order model.