# PATCH memberships/:id/terms

Save prospective individual terms for a membership. Existing saved referral contracts are not silently rewritten.

## Purpose

Save prospective individual terms for a membership. Existing saved referral contracts are not silently rewritten.

## Authentication and scope

Use an app-scoped affiliate API key with `terms:write`. Record IDs must belong to the credential's app and workspace. A workspace MCP key or install-bridge key is not interchangeable with this key.

## Request

`PATCH /api/affiliate-platform/v1/memberships/:id/terms`

- `rules`: required; object
- `effectiveAt`: optional; value

Use the exact record identifier returned for your own app.

## Example

Set the environment credential from your authenticated Developers screen. Replace the fictional record IDs and shop/contact values. This request changes data; review the effect before running it. Use a new idempotency key for a new action, and reuse the same key/body only when retrying the same action.

```bash
curl --request PATCH "https://heycrust.com/api/affiliate-platform/v1/memberships/11111111-1111-4111-8111-111111111111/terms" \
  --header "Authorization: Bearer $HEYCRUST_AFFILIATE_API_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: example-patch-memberships-id-terms-001" \
  --data '{"rules":{"basis":"gross","rateBps":2000,"cpi":{"amountMinor":"0","currency":"USD"},"includedSaleKinds":["subscription_sale"],"durationMonths":12,"holdDays":30,"threshold":{"amountMinor":"5000","currency":"USD"},"windowDays":30,"allowExistingShops":false,"allowManualClaims":true}}'
```

## Response and verification

The response is the operation's program, membership, terms, referral, commission or payout-history representation. Verify its app/record identity and state; acceptance of a request is not proof of an external transfer or attributed Shopify install.

Successful responses use `Cache-Control: no-store` and `X-Affiliate-Schema-Version: 1`. Money uses currency plus minor-unit integer strings; currencies stay separate.

## Errors and recovery

401 means missing/invalid/revoked credentials; 403 means denied app/scope/resource access. Invalid fields produce 400, unsupported operation/path 404, conflict/source/review conditions 409, and the DB-backed credential quota produces 429 with `Retry-After`. The public affiliate quota is 120 requests per credential per minute. Validate the response body as well as the status. JSON mutation bodies must fit the 65,536-byte request bound.

Read [API overview](/docs/api) and [Developer integration](/docs/developers).

## Response example

Successful response excerpt exercised through the actual handler with isolated fixtures. Other fields are omitted. IDs, dates and merchant values are fictional; this is an example state, not a universal outcome.

```json
{
  "id": "11111111-1111-4111-8111-111111111111",
  "programId": "11111111-1111-4111-8111-111111111111",
  "target": {
    "kind": "membership",
    "id": "11111111-1111-4111-8111-111111111111"
  },
  "rules": {
    "basis": "gross",
    "rateBps": 2000,
    "durationMonths": 12,
    "holdDays": 30
  },
  "effectiveAt": "2026-10-07T10:00:00.000Z"
}
```

## Complete rules and business constraints

Send the full rules object. Schema acceptance is followed by financial business validation; an object with the right JSON types can still be rejected. Percentage units are basis points: **2000 means 20%, while 20 means 0.2%**. Review the intended basis, charge kinds, duration and hold before a write.

| Field | Required meaning and constraints |
| --- | --- |
| `rules.basis` | Required: gross or net. Gross uses the eligible gross collection basis shown by the product; net uses the corresponding net collection. No FX conversion is invented. |
| `rules.rateBps` | Required integer basis points from 0 to 10000. 2000 = 20%; 3000 = 30%; 20 = 0.2%. A zero rate requires a positive CPI reward. |
| `rules.cpi` | Required Money object; amountMinor is a nonnegative integer string and currency is a supported uppercase settlement currency. Zero disables the install reward. |
| `rules.cpi.amountMinor` | Required nonnegative minor-unit integer string, at most 38 digits; no leading zeros except 0 and no negative zero. |
| `rules.cpi.currency` | Required supported settlement currency such as USD. Its scale determines minor units; the object has no precision field. |
| `rules.includedSaleKinds` | Required array containing unique subscription_sale, usage_sale and/or one_time_sale values. Must be nonempty when rateBps is positive. |
| `rules.durationMonths` | Required positive integer 1–1200 or null for unlimited duration. Calendar anniversaries use the original install date; zero does not mean lifetime. |
| `rules.holdDays` | Required integer 0–3650: collection holding period in days. |
| `rules.threshold` | Required nonnegative Money object for the primary payout threshold. Uses amountMinor and supported currency. |
| `rules.threshold.amountMinor` | Required nonnegative canonical minor-unit integer string, at most 38 digits. |
| `rules.threshold.currency` | Required supported uppercase settlement currency; keep balances separate. |
| `rules.windowDays` | Required integer 1–365: attribution/referral window in days. |
| `rules.allowExistingShops` | Required boolean: eligibility policy for existing shops. |
| `rules.allowManualClaims` | Required boolean: program-level manual client-claim policy; effective group/membership permissions also matter. |
| `rules.thresholds` | Optional array of at most 30 Money objects. One nonnegative threshold per currency; currencies must be unique and the primary threshold must be included with the exact same amount. Omission derives the primary threshold only. |
| `rules.thresholds[].amountMinor` | Required for each listed threshold: nonnegative canonical minor-unit integer string. |
| `rules.thresholds[].currency` | Required for each listed threshold: supported currency; no duplicates in the array. |
| `effectiveAt` | Optional ISO datetime; omission uses request time. New rules cannot be retroactive. These are prospective versions, not a rewrite of saved referral contracts. |

An effective version may change future offers/eligibility; existing referrals retain their contract snapshot unless a separate reviewed future-contract proposal is accepted. The public API does not interpret rateBps as a whole percentage. See [Program contracts](/docs/app-owners/programs-and-terms) and [Exact money](/docs/help/data-and-states#minor-unit-examples).
