Payments

Update recurring payment

Changed on

Updates an SDP-custody recurring payment. Pending records are updated directly. Active metadata and due-date edits are applied in place, while active term, source, destination, or token edits create a replacement Solana subscription, authorize it, cancel the old subscription, and then swap the recurring payment to the replacement records. Requires an Idempotency-Key, because an edit can sign and broadcast a replacement subscription. A same-key retry of a completed edit replays its answer. A retry of an interrupted edit gets 409 IDEMPOTENCY_KEY_IN_FLIGHT with Retry-After until the attempt is stale, then resumes from the last step SDP recorded. If a step was sent but not yet recorded when the edit was interrupted, which is rare, the retry can fail or send that step again, so read the recurring payment with GET before editing it again.

patch/v1/payments/recurring-payments/{id}

Request

  • Base URL
    http://localhost:8787
  • URL
    http://localhost:8787/v1/payments/recurring-payments/{id}
  • Auth
    HTTP bearer

Path parameters

idstring required

SDP recurring payment record ID.

Example:prp_example

Headers

x-project-idstring

Required for dashboard sessions. API keys use their assigned project.

Example:prj_example
Idempotency-Keystring required

Required: a request without one returns 400 IDEMPOTENCY_KEY_REQUIRED. 1-255 printable ASCII characters; send a UUID per logical operation and reuse it on every retry. Within 24 hours, a retry with the same key and the same request returns the stored status and body with the response header Idempotent-Replayed: true. Keys are scoped to the credential: within 24 hours, the same key with a different request, or from a different credential, returns 422 IDEMPOTENCY_KEY_REUSED; after that, the same key from a different credential runs as a new request. A rotated API key is a new credential, so after any rotation read the resource with GET to see whether the original request ran, and never resend a money request under the new credential without checking first. A key whose original request is still running returns 409 IDEMPOTENCY_KEY_IN_FLIGHT with Retry-After. A 400, 401, 403, 409 or 429 refusal is not stored, so the same key runs again once the cause is fixed. Access is checked before the key on every request, so a refused request never claims the key, and a credential that has since lost access to the named resource gets 403 instead of the stored response. A replay is a snapshot of the original response: read the current state with GET instead of sending the request again. If the original request never recorded its outcome (it crashed), a same-key retry gets 409 IDEMPOTENCY_KEY_IN_FLIGHT until 15 minutes plus the route's lease have passed since the original was sent (about 16 minutes, or about 20 for transfer batches), then takes over and is answered from the record it wrote. After a 5xx, a retry with the same key runs again and answers from the original record instead of acting twice; that answer also carries Idempotent-Replayed: true.

Example:idempotency_example_12345

Request body

sourceCustodyWalletIdstring

Optional exact replacement SDP Wallet ID (id from GET /v1/wallets). Provider walletId, wallet addresses, and the legacy sourceWalletId selector are not accepted. Active replacements require write access to both the old and new source wallets.

counterpartyIdstring

Optional replacement counterparty. When provided, counterpartyAccountId is also required.

counterpartyAccountIdstring

Optional replacement counterparty account. Without counterpartyId, this changes the account for the current counterparty.

tokenstring

Optional replacement token. Must be a USD stablecoin (e.g. USDC) or a token issued in this project; native SOL is not supported.

amountstring

Optional replacement amount in UI units.

periodHoursinteger

Optional replacement billing period length in hours. Active term changes create a replacement on-chain subscription.

firstCollectionAtstring date-time nullable

Pending-only first collection timestamp. Use null to clear the pending first collection override.

nextCollectionDueAtstring date-time nullable

Active-only next due timestamp. Use null to reset to the earliest eligible collection time.

metadataUristring uri nullable

Optional plan metadata URI. Use null to clear it. Active metadata-only edits update the existing on-chain plan in place.

Example request

{
  "sourceCustodyWalletId": "cwlt_example",
  "counterpartyId": "cpty_example",
  "counterpartyAccountId": "cpacct_example",
  "token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "amount": "25.00",
  "periodHours": 720,
  "firstCollectionAt": "2099-01-01T00:00:00.000Z",
  "nextCollectionDueAt": "2099-02-01T00:00:00.000Z",
  "metadataUri": "https://example.com/subscriptions/monthly-usdc.json"
}

Response

Recurring payment updated

Example response

{
  "data": {
    "recurringPayment": {
      "id": "prp_example",
      "organizationId": "org_example",
      "projectId": "prj_example",
      "sourceCustodyWalletId": "cwlt_example",
      "sourceProviderWalletId": "privy_wallet_123",
      "sourceAddress": "So11111111111111111111111111111111111111112",
      "counterpartyId": "cpty_example",
      "counterpartyAccountId": "cpacct_example",
      "destinationAddress": "So11111111111111111111111111111111111111112",
      "destinationTokenAccount": "So11111111111111111111111111111111111111112",
      "amount": "100.00",
      "periodHours": 720,
      "firstCollectionAt": "2025-01-01T00:00:00.000Z",
      "nextCollectionDueAt": "2025-01-01T00:00:00.000Z",
      "planPda": "So11111111111111111111111111111111111111112",
      "subscriptionPda": "So11111111111111111111111111111111111111112",
      "subscriptionAuthorityAddress": "So11111111111111111111111111111111111111112",
      "status": "active",
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-01T00:00:00.000Z"
    },
    "tokenApproval": {
      "status": "kept",
      "delegate": "So11111111111111111111111111111111111111112",
      "sharedWith": [
        {
          "id": "prp_example",
          "status": "active"
        }
      ]
    }
  },
  "meta": {
    "requestId": "req_example",
    "timestamp": "2025-01-01T00:00:00.000Z"
  }
}

Changes

    • warning

      added the new CUSTODY_POLICY_REFUSED enum value to the / response property for the response status

    • warning

      added the new CUSTODY_POLICY_REFUSED enum value to the / response property for the response status

    • warning

      added the new CUSTODY_POLICY_REFUSED enum value to the / response property for the response status

    • warning

      added the new CUSTODY_POLICY_REFUSED enum value to the / response property for the response status

    • warning

      added the new CUSTODY_POLICY_REFUSED enum value to the / response property for the response status

    • warning

      added the new CUSTODY_POLICY_REFUSED enum value to the / response property for the response status

    • warning

      added the new CUSTODY_POLICY_REFUSED enum value to the / response property for the response status

    • info

      added the optional property / to the response with the status

    • info

      added the required property // to the response with the status

    • warning

      added the new RPC_UNAVAILABLE enum value to the / response property for the response status

    • warning

      added the new RPC_UNAVAILABLE enum value to the / response property for the response status

    • warning

      added the new RPC_UNAVAILABLE enum value to the / response property for the response status

    • warning

      added the new RPC_UNAVAILABLE enum value to the / response property for the response status

    • warning

      added the new RPC_UNAVAILABLE enum value to the / response property for the response status

    • warning

      added the new RPC_UNAVAILABLE enum value to the / response property for the response status

    • warning

      added the new RPC_UNAVAILABLE enum value to the / response property for the response status

    • warning

      added the new SPONSORED_RENT_OVER_CAP enum value to the / response property for the response status

    • warning

      added the new SPONSORED_RENT_OVER_CAP enum value to the / response property for the response status

    • warning

      added the new SPONSORED_RENT_OVER_CAP enum value to the / response property for the response status

    • warning

      added the new SPONSORED_RENT_OVER_CAP enum value to the / response property for the response status

    • warning

      added the new SPONSORED_RENT_OVER_CAP enum value to the / response property for the response status

    • warning

      added the new SPONSORED_RENT_OVER_CAP enum value to the / response property for the response status

    • warning

      added the new SPONSORED_RENT_OVER_CAP enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_DESTINATION_CHANGED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_DESTINATION_CHANGED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_DESTINATION_CHANGED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_DESTINATION_CHANGED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_DESTINATION_CHANGED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_DESTINATION_CHANGED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_DESTINATION_CHANGED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_NOTHING_TO_RETRY enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_NOTHING_TO_RETRY enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_NOTHING_TO_RETRY enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_NOTHING_TO_RETRY enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_NOTHING_TO_RETRY enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_NOTHING_TO_RETRY enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_NOTHING_TO_RETRY enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RETRY_CLAIMED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RETRY_CLAIMED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RETRY_CLAIMED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RETRY_CLAIMED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RETRY_CLAIMED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RETRY_CLAIMED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RETRY_CLAIMED enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RUN_EXISTS enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RUN_EXISTS enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RUN_EXISTS enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RUN_EXISTS enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RUN_EXISTS enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RUN_EXISTS enum value to the / response property for the response status

    • warning

      added the new TRANSFER_BATCH_RUN_EXISTS enum value to the / response property for the response status