# Revise a partner's terms

`POST /lokta-lms/api/v1/sourcing-partners/{partnerId}/terms`

Writes a new terms version for a sourcing partner and closes the one it supersedes.

Writes a new version with its lines and slabs, and closes the one it supersedes on the day before this one starts; one transaction, both halves or neither. There is no PUT and no PATCH: a fee that has already accrued cites the version that produced it, so editing a version in place would make a paid invoice unexplainable.

Scope matters. A revision closes only the predecessor with the same `product_id`; the default agreement (`product_id: null`) and a product override are separate lineages, and revising one must not close the other.

`effective_from` must be strictly after the version being superseded; otherwise the handover would leave a window with two active agreements or none, and a fee run over that window would pick one arbitrarily. That is a `409 sourcing/terms_overlap`.

Lookups arrive as bare codes here (`"basis": "DISBURSED_PRINCIPAL"`, `"guarantee": {"form": "CASH_DEPOSIT"}`) and come back as `{code, label}` objects on the read; a caller states which value it means, a reader needs the label to render. `method` and `accrual_frequency` are accepted in either case.

`line_no` is not accepted: lines are numbered from their order in the array, because a client-supplied number is a second source of truth for order that can disagree with the array it arrived in. Slab bands likewise take no `order_position`; they are ordered, and checked for contiguity, by `from_principal`.

Refusals worth knowing: an agreement with no line is `422 sourcing/terms_line_required`; a fee shape that contradicts its method is `422 sourcing/fee_shape_invalid`; bands that do not tile from zero with exactly one open top are `422 sourcing/slab_coverage_invalid`; a guarantee above 5% or beyond 120 days is refused as regulatory law, not policy.

Requires an `Idempotency-Key`. Reusing a key with a different body is a `409`, never a silent replay; on this endpoint a silent replay would hide a second, different agreement.

## When to use it

Use this to add the agreement a partner is paid under. Activation is refused until an agreement is in force.

## Worth knowing
- Terms are versioned. There is no update: a revision writes a new version and closes the one before it.
- Send an Idempotency-Key header.

## Parameters
- `partnerId` (path, string, required): Opaque partner id, spr_…
- `Idempotency-Key` (header, string): Per-intent key; persist it before sending and reuse it on retry

## Request body (application/json)
- `product_id` (integer): The loan product this agreement covers. Null is the partner's default agreement.
- `effective_from` (string): The date this version starts. It must be after the version it supersedes.
- `method` (string): The fee method. Accepted in either case.
- `accrual_frequency` (string): How often fees accrue. Accepted in either case.
- `guarantee` (object): A single object, or null. Its form is a code such as CASH_DEPOSIT.
- `lines` (array): The fee lines. They are numbered from their order in the array, so send no line_no.

## Responses
- `default`: default response

## Example request (cURL)
```bash
curl -X POST \
  'https://default.lokta.tech/lokta-lms/api/v1/sourcing-partners/{partnerId}/terms' \
  -u '{username}:{password}' \
  -H 'Tenant-Identifier: default' \
  -H 'Content-Type: application/json' \
  -d '{
  "product_id": 1,
  "effective_from": "string",
  "method": "string",
  "accrual_frequency": "string",
  "guarantee": {
    "form": "string"
  },
  "lines": [
    {
      "basis": "string",
      "slabs": []
    }
  ]
}'
```

Interactive: https://developer.lokta.ai/reference#operation/revise
