Milestone Disbursement Engine (core) (0.2.0)

Download OpenAPI specification:

License: AGPL-3.0-only

The core flow an SDK covers: draft and confirm an agreement, fund a tranche, submit evidence, read the verdict, review and release. Turns an agreement into checkable acceptance criteria, verifies evidence against them, and settles each tranche through PayPal.

Conventions

  • Authentication: Authorization: Bearer <token>, where the token is a person's session (from a magic link or SSO) or an organization API key (POST /orgs/{id}/api-keys). A person who belongs to several organizations sends X-Org-Id to say which one they act for.
  • Errors: every 4xx body is {"detail": "<what went wrong>"} (422 carries FastAPI's field-level list in detail). 401: no or expired token. 403: this org or role may not do that. 404: no such resource, or not yours to see. 409: the resource isn't in a state that allows the call; the detail says what state it is in. 429: rate limited (Retry-After in seconds).
  • Idempotency and retries: submitting identical evidence is a no-op (duplicate: true). Funding, releasing and paying out are safe to call again: an in-flight attempt is resumed with the same PayPal idempotency key, a finished one answers 409. Confirming with a stale criteria_hash answers 409 with the current criteria.
  • Pagination: none. Lists (ledger, subscriptions, evidence) are per agreement or tranche and returned whole.
  • Money: decimal strings with two places, in the agreement's ISO 4217 currency. Times are ISO 8601 with offset.

agreements

Drafting, inviting, reading and signing agreements.

Propose tranches and checkable criteria from an agreement document (PDF or text upload)

Authorizations:
bearerAuth
header Parameters
X-Org-Key (string) or X-Org-Key (null) (X-Org-Key)

Deployment key, required when the server sets one.

Authorization (string) or Authorization (null) (Authorization)
Request Body schema: multipart/form-data
required
file
required
string <application/octet-stream> (File)

The agreement: PDF, plain text or Markdown, up to 20 MB.

Responses

Response samples

Content type
application/json
{
  • "currency": "string",
  • "lint": {
    },
  • "milestones": [
    ],
  • "model": "string",
  • "open_questions": [
    ],
  • "problems": [
    ],
  • "provenance": [
    ],
  • "title": "string",
  • "total_amount": "string"
}

Propose tranches and checkable criteria from an agreement's text

Authorizations:
bearerAuth
header Parameters
X-Org-Key (string) or X-Org-Key (null) (X-Org-Key)

Deployment key, required when the server sets one.

Authorization (string) or Authorization (null) (Authorization)
Request Body schema: application/json
required
text
required
string (Text) [ 20 .. 200000 ] characters

Full text of the grant agreement or SOW.

title
string (Title) <= 200 characters
Default: "agreement"

File name or title, for provenance.

Responses

Request samples

Content type
application/json
{
  • "text": "GRANT AGREEMENT between Harbor Foundation and Riverside Reads ... Tranche 1 (USD 10,000) is payable when ...",
  • "title": "Riverside grant.txt"
}

Response samples

Content type
application/json
{
  • "currency": "string",
  • "lint": {
    },
  • "milestones": [
    ],
  • "model": "string",
  • "open_questions": [
    ],
  • "problems": [
    ],
  • "provenance": [
    ],
  • "title": "string",
  • "total_amount": "string"
}

Agreement, tranches, criteria, lint and confirmation status

Authorizations:
bearerAuth
path Parameters
agreement_id
required
string (Agreement Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)

Responses

Response samples

Content type
application/json
{
  • "auto_release_enabled": true,
  • "auto_release_threshold": 0.85,
  • "criteria_hash": "string",
  • "currency": "USD",
  • "deliverable_release": "on_submit",
  • "dispute_window_days": 0,
  • "funding": {
    },
  • "id": "string",
  • "lint": {
    },
  • "locked": true,
  • "milestones": [
    ],
  • "min_evidence_visibility": "hash_only",
  • "parties": [
    ],
  • "pending_invitations": [
    ],
  • "require_reviewer_approval": false,
  • "reviewer_decides_withheld": true,
  • "settlement_mode": "escrow_release",
  • "source_document_uri": "string",
  • "status": "draft",
  • "title": "string",
  • "total_amount": "string"
}

Sign the current criteria hash for your org; activates when every party has signed

Authorizations:
bearerAuth
path Parameters
agreement_id
required
string (Agreement Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)
Request Body schema: application/json
required
Auto Release Enabled (boolean) or Auto Release Enabled (null) (Auto Release Enabled)

Payer only: allow confident verdicts to release without a human.

criteria_hash
required
string (Criteria Hash)

The criteria_hash this party reviewed and agrees to.

Responses

Request samples

Content type
application/json
{
  • "auto_release_enabled": false,
  • "criteria_hash": "3f1c…e9a2"
}

Response samples

Content type
application/json
{
  • "auto_release_enabled": true,
  • "auto_release_threshold": 0.85,
  • "criteria_hash": "string",
  • "currency": "USD",
  • "deliverable_release": "on_submit",
  • "dispute_window_days": 0,
  • "funding": {
    },
  • "id": "string",
  • "lint": {
    },
  • "locked": true,
  • "milestones": [
    ],
  • "min_evidence_visibility": "hash_only",
  • "parties": [
    ],
  • "pending_invitations": [
    ],
  • "require_reviewer_approval": false,
  • "reviewer_decides_withheld": true,
  • "settlement_mode": "escrow_release",
  • "source_document_uri": "string",
  • "status": "draft",
  • "title": "string",
  • "total_amount": "string"
}

Invite a reviewer (or the payee, if none has joined) to this agreement (payer admin)

Authorizations:
bearerAuth
path Parameters
agreement_id
required
string (Agreement Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)
Request Body schema: application/json
required
email
required
string (Email) <= 320 characters ^[^@\s]+@[^@\s]+\.[^@\s]+$

Who to invite.

kind
string (Kind)
Default: "reviewer"
Enum: "counterparty" "reviewer"

counterparty: the payee (replaces a pending payee invitation); reviewer.

Responses

Request samples

Content type
application/json
{
  • "email": "auditor@sponsor.example.org",
  • "kind": "reviewer"
}

Response samples

Content type
application/json
{
  • "invitation": {
    }
}

Create a draft agreement as this org (the payer) and invite the payee and any reviewers

Authorizations:
bearerAuth
path Parameters
org_id
required
string (Org Id)
header Parameters
Authorization (string) or Authorization (null) (Authorization)
Request Body schema: application/json
required
auto_release_threshold
number (Auto Release Threshold) [ 0 .. 1 ]
Default: 0.85

Minimum gate score to settle without human approval.

counterparty_email
required
string (Counterparty Email) <= 320 characters ^[^@\s]+@[^@\s]+\.[^@\s]+$

Email of the person invited to accept for the payee organization.

currency
string (Currency) <= 3 characters ^[A-Z]{3}$
Default: "USD"

ISO 4217 currency.

deliverable_release
string (DeliverableRelease)
Default: "on_submit"
Enum: "on_submit" "on_capture"

When the payer can open the payee's full evidence: on_submit (as it arrives; usual for grants) or on_capture (only once the tranche is captured, so the payer pays on the verdict; suggested for SOWs). Part of the criteria hash both parties sign; set when the agreement is created.

dispute_window_days
integer (Dispute Window Days) [ 0 .. 14 ]
Default: 0

Escrow: days between capturing a verified tranche and paying the payee, during which the payer or a reviewer can contest it. 0 pays at once.

required
Array of objects (Milestones) non-empty

Tranches in payment order.

min_evidence_visibility
string (EvidenceVisibility)
Default: "hash_only"
Enum: "hash_only" "verdict_only" "excerpt" "preview"

on_capture only: the least the payee may show the payer of each evidence item before capture. hash_only (pass/fail and the pinned hash), verdict_only (+ observed values), excerpt (+ the verifier's quotes and rationale) or preview. The payee picks a level at or above it per item. Signed with the criteria.

require_reviewer_approval
boolean (Require Reviewer Approval)
Default: false

When on, only a reviewer's approval releases a tranche in review.

reviewer_decides_withheld
boolean (Reviewer Decides Withheld)
Default: true

deliverable_release=on_capture: while a tranche's evidence is withheld from the payer, a tranche in review waits for an invited reviewer's approval (they see all the evidence; the payer can't judge what they can't see, but can still reject). Without a reviewer on the agreement the payer decides as usual.

reviewer_emails
Array of strings (Reviewer Emails)

Optional third-party reviewers to invite (criteria and evidence).

settlement_mode
required
string (SettlementMode)
Enum: "escrow_release" "invoice_on_verify"

escrow_release holds funds per milestone and releases on verify; invoice_on_verify sends a PayPal invoice when a milestone verifies.

Source Document Uri (string) or Source Document Uri (null) (Source Document Uri)

Original agreement file the milestones came from.

title
required
string (Title) [ 1 .. 200 ] characters

Human-readable name of the grant or SOW.

required
Total Amount (number) or Total Amount (string) (Total Amount)

Agreement total; milestones must sum to it.

Responses

Request samples

Content type
application/json
{
  • "auto_release_threshold": 0.85,
  • "counterparty_email": "director@riverside.example.org",
  • "currency": "USD",
  • "milestones": [
    ],
  • "reviewer_emails": [
    ],
  • "settlement_mode": "escrow_release",
  • "title": "Riverside Literacy Grant 2027",
  • "total_amount": "30000.00"
}

Response samples

Content type
application/json
{
  • "agreement": {
    },
  • "invitations": [
    ]
}

evidence

Pre-checks, submissions, verdicts and review decisions on a tranche.

Payee submits evidence for a tranche; verification runs in the background

Authorizations:
bearerAuth
path Parameters
milestone_id
required
string (Milestone Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)
Request Body schema: application/json
required
artifact_uris
Array of strings (Artifact Uris)

Links to the original files or pages.

content
required
string (Content) [ 1 .. 200000 ] characters

Text of the evidence: spreadsheets as CSV with a header row, documents as their text. Untrusted: never followed as instructions.

Dated (string) or Dated (null) (Dated)

The evidence's own date, e.g. report cover or commit date.

evidence_type
required
string (EvidenceType)
Enum: "document" "spreadsheet" "photo" "link" "code_change" "ci_run" "dataset" "attestation"

Kind of evidence, matched against each criterion.

External Ref (string) or External Ref (null) (External Ref)

Source-native id (file id, URL). Defaults to a content hash.

EvidenceVisibility (string) or null

deliverable_release=on_capture: what the payer sees of this item before capture. Defaults to the agreement's min_evidence_visibility and can't be below it. Ignored for on_submit agreements.

Preview Expires At (string) or Preview Expires At (null) (Preview Expires At)

When the preview link stops being shown. Defaults to 30 days after submission.

Preview Url (string) or Preview Url (null) (Preview Url)

A preview the payee hosts for the payer to try (a deployed build, a demo). Shown to the payer side at any visibility, since giving one is the payee's choice to show it; it isn't checked.

title
required
string (Title) [ 1 .. 200 ] characters

File name or short label, e.g. 'Q2 sign-in sheets.csv'.

Responses

Request samples

Content type
application/json
{
  • "content": "session_date,session,attendee,signed\n2027-04-10,Session 1,Ava Nguyen,yes\n...",
  • "dated": "2027-05-22",
  • "evidence_type": "spreadsheet",
  • "title": "Spring workshop sign-in sheets (register).csv"
}

Response samples

Content type
application/json
{
  • "duplicate": false,
  • "evidence_id": "ev_01hx…",
  • "milestone_status": "evidence_received"
}

Payee checks draft evidence against the criteria without submitting it

Authorizations:
bearerAuth
path Parameters
milestone_id
required
string (Milestone Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)
Request Body schema: application/json
required
required
Array of objects (Evidence) non-empty

Draft evidence; nothing is stored.

Responses

Request samples

Content type
application/json
{
  • "evidence": [
    ]
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "criteria_results": [
    ],
  • "gate": "string",
  • "id": "string",
  • "is_precheck": false,
  • "met": true,
  • "model": "string",
  • "model_confidence": 0,
  • "prompt_version": "string",
  • "rationale": "string",
  • "skeptic": {
    },
  • "weighted_share": 0
}

Payer (admin) or reviewer approves or rejects a verdict in review

Authorizations:
bearerAuth
path Parameters
milestone_id
required
string (Milestone Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)
Request Body schema: application/json
required
decision
required
string (Decision)
Enum: "approve" "reject"

approve releases the tranche (it settles when funded); reject sends it back with what's missing.

Note (string) or Note (null) (Note)

Shown to the payee and kept in the audit log.

Responses

Request samples

Content type
application/json
{
  • "decision": "reject",
  • "note": "Table 2 is missing the post-program scores for section B."
}

Response samples

Content type
application/json
{
  • "milestone_status": "funded",
  • "missing": [
    ]
}

Payee uploads evidence files (PDF, CSV, XLSX, TXT, MD, images); verification runs in the background

Authorizations:
bearerAuth
path Parameters
milestone_id
required
string (Milestone Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)
Request Body schema: multipart/form-data
required
Dated (string) or Dated (null) (Dated)

The evidence's own date, if the files don't carry one.

files
required
Array of strings (Files)

Up to 10 files, 20 MB each, 25 MB total.

Note (string) or Note (null) (Note)

Optional context, shown as a payee note.

EvidenceVisibility (string) or null

on_capture agreements: what the payer sees of these files before capture.

Preview Pages (string) or Preview Pages (null) (Preview Pages)

payer_visibility=preview: the PDF pages the payer's preview shows, e.g. '1-2,5' (at most 5; default the first two). Images and spreadsheets get their own previews.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Latest verdict for a tranche, with per-criterion results and citations

Authorizations:
bearerAuth
path Parameters
milestone_id
required
string (Milestone Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "criteria_results": [
    ],
  • "gate": "string",
  • "id": "string",
  • "is_precheck": false,
  • "met": true,
  • "model": "string",
  • "model_confidence": 0,
  • "prompt_version": "string",
  • "rationale": "string",
  • "skeptic": {
    },
  • "weighted_share": 0
}

settlement

Funding, releasing and paying out a tranche; the ledger.

Every PayPal money movement and settlement attempt on an agreement

Authorizations:
bearerAuth
path Parameters
agreement_id
required
string (Agreement Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)

Responses

Response samples

Content type
application/json
{
  • "currency": "string",
  • "disbursements": [
    ],
  • "entries": [
    ],
  • "settlements": [
    ]
}

Payer starts a PayPal hold for one tranche

Authorizations:
bearerAuth
path Parameters
milestone_id
required
string (Milestone Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)

Responses

Response samples

Content type
application/json
{}

Pay a captured tranche to the payee now (waives the rest of the dispute window; retries a failed payout)

Authorizations:
bearerAuth
path Parameters
milestone_id
required
string (Milestone Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)

Responses

Response samples

Content type
application/json
{
  • "attempt": 1,
  • "id": "string",
  • "idempotency_key": "string",
  • "kind": "referenced_payout",
  • "milestone_status": "pending",
  • "paypal_ref": "string",
  • "status": "submitted"
}

Settle a verified tranche: capture its hold or send its invoice (also resumes a failed release)

Authorizations:
bearerAuth
path Parameters
milestone_id
required
string (Milestone Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)

Responses

Response samples

Content type
application/json
{
  • "attempt": 1,
  • "id": "string",
  • "idempotency_key": "string",
  • "milestone_status": "pending",
  • "mode": "escrow_release",
  • "pay_url": "string",
  • "paypal_ref": "string",
  • "status": "submitted"
}

events

Signed outbound webhooks for an agreement's events.

Subscriptions on this agreement

Authorizations:
bearerAuth
path Parameters
agreement_id
required
string (Agreement Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Subscribe a URL to this agreement's events

Authorizations:
bearerAuth
path Parameters
agreement_id
required
string (Agreement Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)
Request Body schema: application/json
required
events
Array of strings (Events)

Event types (milestone.status_changed), prefixes ending in '.' (milestone.), or '*'.

url
required
string (Url) <= 1000 characters

HTTPS endpoint that receives signed JSON events.

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{
  • "active": true,
  • "created_at": "2019-08-24T14:15:22Z",
  • "events": [
    ],
  • "id": "string",
  • "secret": "string",
  • "url": "string"
}

Remove a subscription; deliveries to it stop

Authorizations:
bearerAuth
path Parameters
agreement_id
required
string (Agreement Id)
subscription_id
required
string (Subscription Id)
header Parameters
X-Org-Id (string) or X-Org-Id (null) (X-Org-Id)

Which of your orgs you act for, if you belong to several.

Authorization (string) or Authorization (null) (Authorization)

Responses

Response samples

Content type
application/json
{
  • "detail": "string"
}