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
IntentCreationSignV2payload (Harbor v1) or the policy-bound v3 variant (V1-006). The signed payload commits to BLAKE3 digests of canonical JSON forbudget,evidence_schema, andpredicate_dsl, plus amount, currency, deadline, tenant, DIDs, andpredicate_ref. - Harbor validates the predicate document (size, fuel, nesting) with
paybond-predicate-vmbefore persisting. - Idempotency is keyed on
(tenant_id, "POST /intents", idempotency-key); a retry with the same body replays the original201.
2. Fund (funded)
- In Stripe Connect mode Harbor authorizes a PaymentIntent on the tenant's connected account. The intent moves to
fundedwhen 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_dslusing the sandboxed VM. The response includes apredicate_evaluationreport withpassedand a trace. passed: trueenables the release transition.passed: falsewith a well-formed request is not an error — it moves the intent toevidence_submittedwith the recorded failure, and the operator may refund or dispute.
4. Confirm settlement (POST /intents/{id}/settlement/confirm)
outcome: releasecaptures the Stripe PaymentIntent (or books the internal release) and moves the intent toreleased.outcome: refundcancels or refunds the PaymentIntent and moves the intent torefunded.- 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
fundedorevidence_submitted, freezing settlement and transitioning todisputed. - 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 (
releaseorrefund) or recordresolved_split/escalated_externalfor non-rail outcomes.
Terminal outcomes
| State | Meaning |
|---|---|
released | Funds captured to the payee. Signal treats the intent as a "released" terminal. |
refunded | Funds returned to the principal. Signal treats as "refunded" terminal. |
resolved_split | Off-rail outcome (for example mixed partial refund handled manually). Signal treats as "disputed" terminal for scoring purposes. |
escalated_external | Handed 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
| Version | Payload | Notes |
|---|---|---|
IntentCreationSignV2 | bincode v2; commits to BLAKE3 digests of canonical JSON for budget, evidence_schema, predicate_dsl | Current wire format. |
IntentCreationSignV3 | Adds 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=stucklists rows that need attention after a crash or Stripe outage.- All mutating POSTs honor
idempotency-keywith per-tenant, per-operation scope. Seeharbor-idempotency-openapi.yaml.
Related
- Harbor API (intents, evidence, settlement, disputes)
- Predicate DSL
- Ledger & provenance
- Operations runbook §1 — settlement & recovery