Activate recurring payment
Activates a pending SDP-custody recurring payment by creating the Solana subscriptions plan, authorizing the subscription, and storing the resulting on-chain identifiers and signatures.
POST/Run in dashboard
A fresh activation signs the terms it read: when an edit lands while it runs, or expectedUpdatedAt names an earlier version, it returns 409 RECURRING_PAYMENT_CHANGED before claiming the schedule or signing.
Both the counterparty and its account must be active before a fresh activation; an unavailable recipient returns 404 before claiming the schedule or signing. Recovery can confirm saved transactions, but cannot sign a new step for an unavailable recipient.
The source wallet gives the Subscriptions program's authority for that token an approval of 0, and each collection approves exactly its own amount in the same transaction as the pull, so the token program's Approve instruction appears in activation and collection transactions. If your custody provider's wallet policy allowlists programs or instructions, allow Approve to that authority, or the provider refuses the collection and SDP pauses the recurring payment with pausedReason custody_policy_refused.
Requires an API key with the recurring.execute action.
Path parameters
-
id·string· required · min length 1 · exampleprp_exampleSDP recurring payment record ID.
Headers
-
x-project-id·string· min length 1 · exampleprj_exampleRequired for dashboard sessions. API keys use their assigned project.
-
Idempotency-Key·string· requiredUse a unique 1–255 printable ASCII key per operation. Reuse it with the same request on retries. An in-flight attempt returns
409; a changed request returns422. Retry and recovery rules.
Request body
application/json
Optional precondition for activating a recurring payment.
-
expectedUpdatedAt·string· min length 1 · max length 64Optional
updatedAtof the version you reviewed, from the last read of this recurring payment. When the recurring payment has changed since, the request returns409RECURRING_PAYMENT_CHANGEDwith the currentupdatedAtinerror.detailsand changes nothing: read it again and review the current terms.
Responses
-
200Recurring payment activated-
data·object· requiredRecurring payment response payload.
-
recurringPayment·object· requiredSDP-custody outbound recurring payment record.
-
id·string· required · exampleprp_exampleSDP recurring payment ID.
-
organizationId·string· required · min length 1 · exampleorg_exampleOrganization identifier.
-
projectId·string· required · min length 1 · exampleprj_exampleProject identifier.
-
sourceCustodyWalletId·string | null· required · examplecwlt_exampleExact source SDP Wallet ID, or null for unresolved legacy records.
-
sourceProviderWalletId·string· required · min length 1 · exampleprivy_wallet_123Source Provider wallet ID retained as evidence.
-
sourceAddress·string· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112Source wallet address.
-
counterpartyId·string· required · examplecpty_exampleCounterparty ID.
-
counterpartyAccountId·string· required · examplecpacct_exampleCounterparty account ID.
-
destinationAddress·string· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112Counterparty wallet owner address.
-
destinationTokenAccount·string | null· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112Derived counterparty token account used for collection.
-
token·string· requiredSPL token mint address.
-
amount·string· required · example100.00Token amount in UI units (decimal string).
-
periodHours·integer· required · greater than 0 · example720 -
firstCollectionAt·string | null· required · formatdate-time· example2025-01-01T00:00:00.000ZRequested first collection timestamp.
-
nextCollectionDueAt·string | null· required · formatdate-time· example2025-01-01T00:00:00.000ZNext due collection timestamp.
-
planId·string | null· requiredLinked SDP subscription plan ID.
-
subscriptionId·string | null· requiredLinked SDP subscription ID.
-
planPda·string | null· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112On-chain plan PDA.
-
planCreatedAt·string | null· requiredOn-chain plan createdAt value as an unsigned integer string.
-
planCreationSignature·string | null· requiredSolana signature for plan creation.
-
subscriptionPda·string | null· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112On-chain subscription PDA.
-
subscriptionAuthorityAddress·string | null· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112On-chain subscription authority address.
-
authorizationSignature·string | null· requiredSolana signature for subscription authorization.
-
status·string· required · one ofpending_activation,activating,active,updating,canceling,resuming,paused,canceled,expired· exampleactiveRecurring payment status.
-
pausedReason·string | null· required · one ofcustody_policy_refused,failed_attempts,destination_unavailable· examplenullWhy SDP paused the recurring payment, set exactly while
statusispaused:custody_policy_refusedwhen the custody provider's policy refused to sign a collection,failed_attemptswhen one due period failed 5 times, ordestination_unavailablewhen its counterparty or account is archived or unavailable in the project. Resume requires an active recipient and clears the reason. -
metadataUri·string | null· requiredOptional plan metadata URI.
-
createdBy·string | null· requiredCreator user ID or API key ID.
-
createdAt·string· required · formatdate-time· example2025-01-01T00:00:00.000ZISO 8601 timestamp.
-
updatedAt·string· required · formatdate-time· example2025-01-01T00:00:00.000ZISO 8601 timestamp.
-
-
tokenApproval·objectPresent when the recurring payment is canceled, on the cancel response and on get: what became of the token approval it relied on.
-
status·string· required · one ofrevoked,kept,revoking· examplekeptrevokedonce the approval has been revoked since the cancel.keptwhile other live recurring payments on the same wallet and token, in this or another project, still use it;sharedWithlists the ones in this project. It is revoked once the last of them ends.revokingwhen nothing else uses it but the revoke has not confirmed yet, for example while a collection that was already processing settles; the background sweep finishes it. -
delegate·string· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112The approval's delegate: the Subscriptions program's authority for this wallet and token.
-
sharedWith·object[]· requiredThe other live recurring payments in this project on the same wallet and token that keep the approval. Empty unless
statusiskept, and empty then when only recurring payments in other projects keep it.-
id·string· required · exampleprp_exampleSDP recurring payment ID.
-
status·string· required · one ofpending_activation,activating,active,updating,canceling,resuming,paused,canceled,expired· exampleactiveRecurring payment status.
-
-
-
-
meta·object· requiredResponse metadata.
-
requestId·string· required · min length 1 · examplereq_exampleRequest identifier for tracing.
-
timestamp·string· required · formatdate-time· example2025-01-01T00:00:00.000ZISO 8601 timestamp.
-
-
-
400Bad Request-
error·object· requiredStandard error payload.
-
code·string· requiredMachine-readable error code.
-
message·string· requiredHuman-readable error message.
-
details·objectOptional error details for debugging.
*·any
-
-
meta·object-
requestId·string· min length 1 · examplereq_exampleRequest identifier for tracing.
-
-
-
401UnauthorizedSame fields as
400. -
403Forbidden. Requires therecurring.executeaction: an API key must hold it (a module'smanageorexecutealso covers itsread), and a signed-in member's organization role must include it. Without it the error is INSUFFICIENT_PERMISSIONS anderror.details.actionnames the action. Any other 403 names its own reason.Same fields as
400. -
404Not FoundSame fields as
400. -
409ConflictSame fields as
400. -
422Unprocessable EntitySame fields as
400. -
500Internal Server ErrorSame fields as
400. -
502Bad GatewaySame fields as
400. -
503Service UnavailableSame fields as
400.