paybondpaybond
Sign in

Intent lifecycle

States and transitions for a Paybond intent, from principal signing through release/refund/dispute.

Intent lifecycle

A Paybond intent is the unit of commercial commitment in Harbor. It is created by a principal (the paying party), evaluated against a predicate bound to submitted evidence, and confirmed into a terminal state (released or refunded). Every transition is signed, appended to the ledger, and visible in Signal.

State diagram

stateDiagram-v2
  [*] --> created
  created --> funded: Stripe PaymentIntent authorized
  funded --> evidence_submitted: POST /intents/{id}/evidence
  evidence_submitted --> released: predicate passed, settlement confirmed (release)
  evidence_submitted --> refunded: predicate failed / rejected, confirmed (refund)
  funded --> disputed: dispute opened
  evidence_submitted --> disputed: dispute opened
  disputed --> released: operator resolve (release)
  disputed --> refunded: operator resolve (refund)
  disputed --> resolved_split: non-rail outcome
  disputed --> escalated_external: arbitration handoff
  released --> [*]
  refunded --> [*]
  resolved_split --> [*]
  escalated_external --> [*]

Transitions

1. Create (POST /intents)

  • The principal signs a bincode IntentCreationSignV2 payload (Harbor v1) or the policy-bound v3 variant (V1-006). The signed payload commits to BLAKE3 digests of canonical JSON for budget, evidence_schema, and predicate_dsl, plus amount, currency, deadline, tenant, DIDs, and predicate_ref.
  • Harbor validates the predicate document (size, fuel, nesting) with paybond-predicate-vm before persisting.
  • Idempotency is keyed on (tenant_id, "POST /intents", idempotency-key); a retry with the same body replays the original 201.

2. Fund (funded)

  • In Stripe Connect mode Harbor authorizes a PaymentIntent on the tenant's connected account. The intent moves to funded when Stripe confirms authorization.
  • In internal mode Harbor books a funding entry directly.

3. Submit evidence (POST /intents/{id}/evidence)

  • The payee signs the evidence payload. Harbor evaluates it against the intent's predicate_dsl using the sandboxed VM. The response includes a predicate_evaluation report with passed and a trace.
  • passed: true enables the release transition. passed: false with a well-formed request is not an error — it moves the intent to evidence_submitted with the recorded failure, and the operator may refund or dispute.

4. Confirm settlement (POST /intents/{id}/settlement/confirm)

  • outcome: release captures the Stripe PaymentIntent (or books the internal release) and moves the intent to released.
  • outcome: refund cancels or refunds the PaymentIntent and moves the intent to refunded.
  • Rate-limited; Harbor exposes recovery endpoints when Stripe and Harbor states drift (see Operational surfaces).

5. Dispute (V1-005)

  • A dispute can be opened from funded or evidence_submitted, freezing settlement and transitioning to disputed.
  • The Gateway maintains a tenant-scoped case row with timeline, evidence references, optional internal notes, and a signed arbitration handoff export. See /v1/disputes/cases/* in the Gateway API.
  • Operators resolve money movement through Harbor (release or refund) or record resolved_split / escalated_external for non-rail outcomes.

Terminal outcomes

StateMeaning
releasedFunds captured to the payee. Signal treats the intent as a "released" terminal.
refundedFunds returned to the principal. Signal treats as "refunded" terminal.
resolved_splitOff-rail outcome (for example mixed partial refund handled manually). Signal treats as "disputed" terminal for scoring purposes.
escalated_externalHanded to an external arbitrator. Signal treats as "disputed" terminal.

Signal scores are recomputed on every terminal transition. Latency is terminal_unix_nanos − intent_created_unix_nanos (clamped at zero).

Signing versions

VersionPayloadNotes
IntentCreationSignV2bincode v2; commits to BLAKE3 digests of canonical JSON for budget, evidence_schema, predicate_dslCurrent wire format.
IntentCreationSignV3Adds policy_ref_digest_hex for managed policy registry bindings.V1-006; automatic when predicate_ref is set.

Offline signers must use the canonical JSON rules from harbor_intent_escrow::signing::canonical_intent_creation_message to match Harbor.

Recovery and idempotency

  • Harbor runs a periodic recovery tick (PAYBOND_HARBOR_RECOVERY_TICK_SECS, default 30s) to re-mint capability tokens for funded rows when Stripe metadata is present but the Biscuit is missing.
  • GET /operator/v1/intents?recovery=stuck lists rows that need attention after a crash or Stripe outage.
  • All mutating POSTs honor idempotency-key with per-tenant, per-operation scope. See harbor-idempotency-openapi.yaml.