Claude
Skills
Sign in
Back

guidewire-core-workflow-a

Included with Lifetime
$97 forever

Automate the PolicyCenter account→submission→quote→bind→issue→endorse→renew pipeline including the failure paths — underwriting issues blocking bind, quotes expiring before bind, referrals stuck pending approval, and mid-term endorsements that trigger unexpected premium audit recalculation. Use when building outbound integrations against PolicyCenter Cloud API (CRM-driven submission, broker-portal binding, automated renewal jobs). Trigger with "policycenter automation", "submission to bind", "policy renewal", "policy endorsement", "underwriting issue".

Backend & APIsguidewirepolicycenterunderwritingsubmissionrenewalendorsement

What this skill does


# Guidewire PolicyCenter Workflow

## Overview

Drive the PolicyCenter policy lifecycle through Cloud API and survive the state-transition failures that derail naive automation. This is the workflow used by broker portals to quote-and-bind, by CRMs to push submissions, and by renewal jobs to issue out-of-cycle. Assumes `guidewire-install-auth` provides the bearer token and `guidewire-sdk-patterns` provides the retrying client with checksum round-trip.

Five production failures this skill prevents:

1. **Bind on a quote with open UW issues** — quote API returns `200`, the `underwritingIssues[]` array is non-empty, the client ignores it, bind returns `422 rule-violation`.
2. **Bind on a stale quote** — quotes expire (default 30 days). A submission left open over a holiday returns `422 quote-expired` on bind.
3. **Orphaned submissions on partial failure** — submission → quote succeeds, bind fails, no rollback; the submission sits in `Quoted` status forever, blocking the next attempt.
4. **Renewal outside the renewal window** — calling renewal before the window opens (typically 60–90 days before expiration) returns `422 renewal-window-closed`.
5. **Endorsement premium drift** — mid-term endorsement recalculates premium against current rate plans, which may differ from the rate plan in force at policy inception. The numeric difference surprises downstream finance integrations.

## Prerequisites

- A working auth + SDK layer per `guidewire-install-auth` and `guidewire-sdk-patterns` (`getToken()`, `patchResource()`, `paginate()`, `mapError()`)
- Cloud API roles `pc.account.write`, `pc.submission.write`, `pc.policy.write` assigned to the integration's Service Application
- Knowledge of which **product code** drives the workflow (e.g., `PersonalAuto`, `BOPLine`) — submission shape is product-specific
- For renewal jobs: read access to the renewal-window configuration on the relevant product

## Instructions

Build the workflow as discrete state-transition functions, each fully responsible for surfacing the failure modes of its transition. Compose them with explicit checkpoints — never collapse the pipeline into a single fire-and-forget call.

### 1. Create the account

```typescript
const idempotencyKey = crypto.randomUUID();
const account = await retryable(async () => {
  const res = await fetch(`${BASE}/pc/rest/v1/accounts`, {
    method: "POST",
    headers: { Authorization: `Bearer ${await getToken()}`, "Content-Type": "application/json", "Idempotency-Key": idempotencyKey },
    body: JSON.stringify({ data: { attributes: { accountHolderContact: contact, primaryLocation: address } } }),
  });
  if (!res.ok) throw await mapError(res, "POST", "/pc/rest/v1/accounts");
  return (await res.json()).data;
});
```

The Idempotency-Key prevents duplicate accounts on retry. Persist `account.attributes.accountNumber` and the resource id immediately — both are needed downstream and the resource id is not derivable from the number.

### 2. Create the submission against the account

Submission is product-specific; its `attributes` shape varies. Read the product's submission schema from the API reference rather than hardcoding fields. The submission moves to `Draft` on creation.

```typescript
const submission = await createSubmission(account.attributes.id, {
  productCode: "PersonalAuto",
  effectiveDate: "2026-06-01",
});
```

### 3. Quote the submission and inspect underwriting issues

The most-skipped step in naive automation. The quote response embeds `underwritingIssues[]`; non-empty with `blocksBind: true` means bind will fail.

```typescript
const quoted = await fetch(`${BASE}/pc/rest/v1/jobs/${submission.attributes.id}/quote`, {
  method: "POST",
  headers: { Authorization: `Bearer ${await getToken()}`, "Idempotency-Key": idempotencyKey },
});
const body = (await quoted.json()).data;
const blockingIssues = body.attributes.underwritingIssues?.filter((u: any) => u.blocksBind) ?? [];
if (blockingIssues.length) {
  await routeToReferralQueue(submission, blockingIssues);
  return { status: "referred", issues: blockingIssues };
}
```

Some UW issues are informational and bind succeeds anyway; check the boolean per issue, not the array length. Surface blocking issues to the manual review queue with the originating actor's identity so the underwriter has context.

### 4. Bind within the quote validity window

Quotes carry `attributes.quoteExpirationDate`. Past it, bind returns `422 quote-expired`. Re-quote rather than retry.

```typescript
if (new Date(body.attributes.quoteExpirationDate) < new Date()) {
  return retryQuoteAndBind(submission.attributes.id);
}
const bound = await bindSubmission(submission.attributes.id);
```

After bind, the submission status moves to `Bound` and a Policy resource is created. `bound.attributes.policy.id` is the canonical policy reference for issuance, endorsement, and renewal.

### 5. Issue (commit the bound policy to in-force)

Bind alone does not put the policy in force; issuance is a separate transition. A bound-but-not-issued policy is invisible to billing; downstream invoices will not generate.

```typescript
const issued = await fetch(`${BASE}/pc/rest/v1/policies/${bound.attributes.policy.id}/issue`, {
  method: "POST",
  headers: { Authorization: `Bearer ${await getToken()}`, "Idempotency-Key": idempotencyKey },
});
```

### 6. Endorsement with premium-drift detection

```typescript
const endorsement = await openEndorsement(policyId, effectiveDate);
const requoted = await quoteEndorsement(endorsement.attributes.id);
const oldPremium = currentPolicy.attributes.totalPremium;
const newPremium = requoted.attributes.totalPremium;
if (Math.abs(newPremium - oldPremium) > MATERIAL_DRIFT_THRESHOLD) {
  await emitPremiumDriftEvent({ policyId, oldPremium, newPremium, delta: newPremium - oldPremium });
}
const boundEndorsement = await bindEndorsement(endorsement.attributes.id);
```

Threshold is policy-dependent; finance teams typically want any drift over a few hundred dollars surfaced before bind. Do not silently bind material drifts — they show up as billing surprises.

### 7. Renewal within the renewal window

The renewal window is configured per product line. Hardcoding 60 days is wrong for any product with non-default settings; read the configuration or accept rejection from the API and respond to the `renewal-window-closed` error type.

```typescript
const policy = await fetch(`${BASE}/pc/rest/v1/policies/${policyId}`).then(r => r.json());
const expirationDate = new Date(policy.data.attributes.expirationDate);
const renewalWindowOpens = subDays(expirationDate, 60);
if (new Date() < renewalWindowOpens) throw new Error("renewal-window-not-yet-open");
const renewalJob = await fetch(`${BASE}/pc/rest/v1/policies/${policyId}/renew`, { method: "POST" });
```

## Output

A complete PolicyCenter workflow integration ships with all of the following:

- Discrete state-transition functions: `createAccount`, `createSubmission`, `quoteSubmission`, `bindSubmission`, `issuePolicy`, `openEndorsement`, `bindEndorsement`, `renewPolicy` — each handling its own failures.
- A blocking-UW-issue check before every bind attempt that routes referrals to a manual-review queue rather than retrying.
- Quote-expiry detection that re-quotes rather than retrying a stale quote.
- Premium-drift detection on endorsement with a configurable threshold and a finance-integration event emission.
- Idempotency-Keys generated once per logical operation (one per submission, one per endorsement, one per renewal cycle), reused across retries.
- A submission/policy state-transition log that captures every API response — debugging "why is this stuck" requires the full transition history.

## Examples

### Example 1 — End-to-end happy path

```typescript
const account = await createAccount(contact, address);
const submission = await createSubmission(account.attributes.id, { productCode: "PersonalAuto", effectiveDate });
const quoted = await quoteSubmission(submission.attributes.i

Related in Backend & APIs