Workflow Reference

Supported workflow triggers, request behavior, permissions, and durable stages.

All workflow routes use:

POST /v1/workflows/{workflow}

and require:

Authorization: Bearer <api-key>
Content-Type: application/json
Idempotency-Key: <caller-generated-delivery-key>

Supported Workflows

WorkflowPermissionConcurrencyStages
onboard-domainworkflows:onboard-domainGlobal aws-infrastructure lane; Maps recovery uses google-maps-api-keysregistration, planning, creation, CloudFront setup, ELB linking, platform routing, finalization, Google Maps whitelisting, completion
add-certificateworkflows:add-certificateGlobal aws-infrastructure laneplanning, creation, CloudFront setup, ELB linking, platform routing, finalization
add-domainworkflows:add-domainGlobal aws-infrastructure laneregistration
add-subdomainworkflows:add-subdomainPer executionplanning, approval, Route53
update-lambda-versionworkflows:update-lambda-versionPer target and environmentplanning, update, deployment observation, finalization

The Slack launcher exposes unified onboard-domain, add-subdomain, update-lambda-version, and execution lookup. add-domain and add-certificate remain supported API and internal workflow surfaces. The permission named for a workflow grants submission plus every supported execution interaction for that workflow. See Service Capabilities for contract boundaries and configuration-gated surfaces.

Trigger Response

The first accepted submission returns HTTP 202:

{
  "estimatedDurationSeconds": 1800,
  "executionId": "exec_...",
  "links": {
    "cancel": "/v1/executions/exec_.../cancel",
    "events": "/v1/executions/exec_.../events",
    "self": "/v1/executions/exec_..."
  },
  "stages": [
    "stage-1-registration",
    "stage-1-planning",
    "stage-2-creation",
    "stage-3-cloudfront-setup",
    "stage-4-elb-linking",
    "stage-5-platform-routing",
    "stage-6-finalization",
    "stage-7-google-maps-whitelisting",
    "stage-8-completion"
  ],
  "status": "queued",
  "workflow": "onboard-domain"
}

A completed idempotent replay returns HTTP 200 and the Idempotent-Replay: true header. An equivalent logical request may reuse an execution even when the delivery key is new.

Add Certificate Input

FieldTypeRequiredBehavior
domainStringcomma-separated domain stringYesRemoves spaces, lowercases domains, and rejects duplicates or invalid names.
isKirbybooleanNoDefaults to true; selects Kirby routing behavior when true.
ticketIdcomma-separated positive decimal IDsNoNormalized and deduplicated for Zendesk completion.
recentCertOverrideDomaindomain or nullNoRequests a specific recent certificate candidate, subject to validation.
options.dryRunbooleanNoDefaults to false; computes workflow behavior without provider mutation.
options.skipReadinessCheckbooleanNoDefaults to false; bypasses provider readiness probes when true.

Certificate groups are capped at 30 SAN entries. Alfred selects an issued, in-use certificate with capacity for both the requested domain and wildcard. An invalid explicit override is rejected in favor of a safe alternative. When no safe candidate exists, the workflow plans a new certificate.

Add Domain Input

{
  "domainString": "example.com"
}

Send a bare root/apex domain such as example.com. Do not send a URL such as https://example.com/path, a wildcard such as *.example.com, or a hostname with a leading www such as www.example.com.

The request schema only checks that domainString is non-empty. Alfred trims and lowercases it while creating the canonical execution input, but this is not domain-shape or ownership validation. The workflow's GoDaddy lookup is the authoritative check that the domain belongs to the configured GoDaddy account and is ACTIVE; the workflow stops before Route53 or nameserver mutations when that check fails.

Onboard Domain Input

POST /v1/workflows/onboard-domain accepts one primary domain and the certificate options used by the standalone certificate workflow:

{
  "domain": "example.com",
  "options": {
    "dryRun": false,
    "skipReadinessCheck": false
  },
  "recentCertOverrideDomain": null,
  "ticketId": "12345,67890"
}

domain is trimmed and lowercased and must contain exactly one DNS name. The schema rejects URLs, paths, wildcards, comma-separated names, and malformed DNS names. Alfred derives the certificate domain from that single primary domain; callers cannot provide a second certificate-domain field. Zendesk ticket IDs are normalized and deduplicated.

The workflow records registration before certificate state. An active domain and existing hosted zone are recorded as already registered and onboarding continues. A registration failure stops all certificate mutations.

After infrastructure finalization, Alfred adds https://<domain>/* and https://*.<domain>/* to every configured Kirby and Zapdos Google Maps browser key. The complete key set is preflighted before any write. Each key is limited to 1,200 referrers, equivalent to 600 roots with this two-referrer rule; Alfred warns below 50 remaining roots and does not shard keys. A manual Maps outcome leaves infrastructure successful and Zendesk open for the Maps-only retry.

When onboarding needs a new CloudFront distribution, Alfred calls CreateDistributionWithTags. The runtime IAM principal must allow both cloudfront:CreateDistribution and cloudfront:TagResource; denying the tag action causes the CloudFront stage to fail before a distribution is created. The MicroBrands baseline also attaches its configured WAF ACL, so the principal must allow wafv2:GetWebACL for that ACL ARN. This read permission lets CloudFront validate the association; it does not allow Alfred to change WAF rules.

Add Subdomain Input

{
  "rootDomain": "example.com",
  "subdomains": ["blog", "offers.eu"]
}

rootDomain is normalized to a lowercase DNS name. subdomains contains 1–10 submitted relative labels; labels are normalized and deduplicated in their first-seen order. Wildcards, malformed labels, and complete hostnames ending in the root domain are rejected. For example, subdomains: ["blog"] is valid, while subdomains: ["blog.example.com"] is not: Alfred appends each relative label to rootDomain. The workflow mirrors the root domain's apex Route53 A-alias and does not change certificates, CDN, or platform routing.

Onboarding Outcome

GET /v1/executions/{executionId} includes outcome for onboard-domain executions. The normalized outcome is derived from persisted execution and stage data and contains:

SectionContents
domainPrimary domain and registered, already-registered, not-registered, or unknown state.
certificatePrimary domain, full ARN, compact certificate ID, and created, adopted, not-created, or unknown state.
distributionsKirby and nginx distribution IDs with created, updated, adopted, not-created, or unknown state.
cleanupCleanup state, manual action, old certificate ARN, and remaining attachments when available.
zendeskTicket ID, intended action, and update state.
googleMapsPer-key safe display name and state, aggregate outcome, and minimum remaining root-domain capacity when known.
assistanceDeduplicated structured reasons with platform or requester audience.
top levelExecution ID, execution status, and Workflow SDK run ID when available.

Missing or malformed persisted data produces explicit not-created, not-reached, or unknown values. Alfred does not infer artifacts or assistance from log or error text.

Platform assistance is present only for explicit structured infrastructure manual-required signals. Failed Zendesk completion or correction produces a requester assistance reason containing the ticket ID and intended action. Generic workflow failure does not imply Platform assistance.

Google Maps capacity, authentication, runtime, or provider failures create a requester assistance reason without exposing key resource names. A succeeded onboarding with a manual Maps outcome can call POST /v1/executions/{id}/retry-maps-whitelist; the command reruns only Maps whitelisting and completion.

Errors

StatusErrorMeaning
400missing_idempotency_keyIdempotency-Key was omitted.
400invalid_jsonRequest body is not valid JSON.
400validation_errorThe workflow's Zod schema rejected the body.
401unauthorizedBearer token is missing or invalid.
403forbiddenPrincipal lacks a required permission.
409idempotency_conflictThe key was previously used for a different request.

Use the generated API reference for complete request schemas and examples.

Update Lambda Version

POST /v1/workflows/update-lambda-version changes the numbered Lambda@Edge version on an approved CloudFront fleet. The request body is:

{
  "environment": "test",
  "options": { "dryRun": false },
  "target": "microbrands",
  "version": 43
}

version must be a positive whole number. Alfred resolves the corresponding published Lambda version in us-east-1 and requires it to be active with a successful last update. $LATEST, aliases, zero, negative numbers, and fractions are rejected.

The supported matrix is:

TargetEnvironmentLambda functionFleet selectorBehavior scope
headoutproductionuuid-assignerThe single enabled distribution with alias headout.comDefault and eligible ordered behaviors
headouttestuuid-assigner-testThe single enabled distribution with alias *.test-headout.comDefault and eligible ordered behaviors
microbrandsproductionuuid-assignerDefault cache policy 1e6fcb00-882b-40a4-813a-21d5f61b6142; aliases contain no test hostnameDefault behavior only
microbrandstestuuid-assigner-testThe same cache policy; every alias is test-headout.com or a subdomain of itDefault behavior only
microbrands-booking-flowproductionuuid-assignerDefault cache policy 292abe6a-03d5-4730-86ec-f265f4ef61f9Default behavior only

microbrands-booking-flow has no test environment. For the cache-policy-selected MicroBrands and MicroBrands Booking Flow fleets, a distribution containing both production and test aliases is rejected. kirby.headout.com is denied even if it otherwise matches a selector.

For Headout, Alfred excludes an ordered behavior when its path pattern contains api, assets, or _next, case-insensitively. For both MicroBrands targets, every ordered behavior is outside the update scope. Alfred updates only existing, numbered uuid-assigner or uuid-assigner-test associations that were frozen into the plan. It can repair an environment-function mismatch, but does not attach or detach Lambda functions, add or remove associations, change event types or IncludeBody, or modify any other CloudFront field.

Set options.dryRun to true to resolve the Lambda, discover the fleet, and produce the plan without preparing or submitting a CloudFront write. The default is false.

Planning freezes distribution IDs, aliases, behavior membership, association identity, and the plan hash before mutation. Different target/environment lanes can run concurrently. A different version in an active lane returns 409 active_target_conflict and links the existing execution.

CloudFront submissions run in bounded batches. Cancellation stops future submissions, but Alfred continues observing updates CloudFront already accepted. A failed or canceled execution can retry only unfinished distributions; persisted planning, receipts, and completed peers are reused. After a terminal execution has durable receipts, rollback restores the exact before-ARNs. Restoration fails closed if the receipt target has drifted instead of overwriting an unexpected change.

Update Lambda Version errors

Synchronous trigger errors include the common errors above plus:

StatusErrorMeaning
400invalid_environmentThe target/environment pair is unsupported.
409active_target_conflictAnother version owns the same target/environment lane.
409reservation_replay_pendingAn equivalent reservation exists but is not yet linked to an execution.

Provider planning and mutation run asynchronously. Read the execution and its events for these stable failure codes:

ErrorMeaning
lambda_version_not_foundThe exact active published version was not resolved.
ambiguous_fleetDiscovery matched an unsafe or denied fleet.
mixed_environment_aliasesA cache-policy-selected MicroBrands distribution mixes production and test aliases, or MicroBrands Booking Flow contains a test distribution.
empty_fleetNo eligible distribution matched.
plan_staleThe reviewed fleet, association membership, or plan hash changed.
provider_failureA CloudFront or Lambda provider operation failed.

Runtime AWS permissions

The API runtime needs CloudFront permission to list distributions, list by cache policy, get distributions and their configuration, update distributions, and read deployment status. In IAM action names, these are cloudfront:ListDistributions, cloudfront:ListDistributionsByCachePolicyId, cloudfront:GetDistribution, cloudfront:GetDistributionConfig, and cloudfront:UpdateDistribution. It also needs lambda:ListVersionsByFunction and lambda:GetFunctionConfiguration for numbered uuid-assigner and uuid-assigner-test versions in us-east-1.