Create subscription plan
Creates a recurring-payment subscription plan record.
POST/Run in dashboard
This stores SDP backend state and Solana subscriptions program identifiers; it does not by itself create the on-chain plan.
Requires an API key with the recurring.manage action.
Headers
-
x-project-id·string· min length 1 · exampleprj_exampleRequired for dashboard sessions. API keys use their assigned project.
-
Idempotency-Key·stringUse 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 · required
Creates an SDP subscription plan record. Prepare the on-chain Solana subscriptions program transaction separately with the plan prepare endpoint.
-
ownerWalletId·string· required · min length 1 · examplewal_merchantCustody wallet that owns the Solana subscription plan.
-
token·string· required · exampleEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1vToken mint address. Native SOL is not expected for program-backed subscriptions.
-
amount·string· required · example25.00Recurring charge amount in UI units.
-
periodHours·integer· required · greater than 0 · max 8760 · example720Billing period length in hours.
-
programPlanId·string· pattern^\d+$· example17014118346046923173Unsigned 64-bit decimal program plan identifier used in the Solana subscriptions PDA seed. Defaults to a generated nonzero value.
-
planPda·string· example7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsUOn-chain plan PDA once created.
-
destinationAddress·string· example7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsUOptional destination owner address allowed by the on-chain plan.
-
pullerWalletId·string· min length 1 · examplewal_collectorOptional SDP custody wallet allowed to pull subscription payments.
-
metadataUri·string· formaturi· max length 128 · examplehttps://example.com/subscriptions/monthly-usdc.jsonOptional plan metadata URI.
-
status·string· one ofdraft,active,archived· exampleactiveSubscription plan status.
Responses
-
201Subscription plan created-
data·object· requiredSubscription plan response payload.
-
subscriptionPlan·object· requiredRecurring payment subscription plan record.
-
id·string· required · examplepsp_exampleSDP subscription plan ID.
-
organizationId·string· required · min length 1 · exampleorg_exampleOrganization identifier.
-
projectId·string· required · min length 1 · exampleprj_exampleProject identifier.
-
ownerWalletId·string· required · min length 1 · exampleprivy_wallet_123Provider wallet ID — the
walletIdfield returned by GET /v1/wallets. -
ownerAddress·string· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112Base58-encoded Solana address.
-
token·string· requiredToken mint or normalized token identifier.
-
amount·string· required · example100.00Token amount in UI units (decimal string).
-
periodHours·integer· required · greater than 0 · example720 -
programPlanId·string· required · example17014118346046923173Unsigned 64-bit decimal program plan identifier used in PDA derivation.
-
planPda·string | null· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112On-chain plan PDA.
-
destinationAddress·string | null· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112Allowed destination owner address.
-
pullerWalletId·string | null· required · min length 1 · exampleprivy_wallet_123Collector wallet ID.
-
pullerAddress·string | null· required · min length 32 · max length 44 · exampleSo11111111111111111111111111111111111111112Collector wallet address.
-
metadataUri·string | null· requiredOptional plan metadata URI.
-
status·string· required · one ofdraft,active,archived· exampleactiveSubscription plan status.
-
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.
-
-
-
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.manageaction: 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.
Example request
curl -X POST 'https://api.solana.com/v1/payments/subscription-plans' \
-H "Authorization: Bearer $SDP_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"ownerWalletId": "wal_merchant",
"token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"amount": "25.00",
"periodHours": 720,
"programPlanId": "17014118346046923173",
"planPda": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"destinationAddress": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"pullerWalletId": "wal_collector",
"metadataUri": "https://example.com/subscriptions/monthly-usdc.json",
"status": "active"
}'Example responses
{
"data": {
"subscriptionPlan": {
"id": "psp_example",
"organizationId": "org_example",
"projectId": "prj_example",
"ownerWalletId": "privy_wallet_123",
"ownerAddress": "So11111111111111111111111111111111111111112",
"token": "example",
"amount": "100.00",
"periodHours": 720,
"programPlanId": "17014118346046923173",
"planPda": "So11111111111111111111111111111111111111112",
"destinationAddress": "So11111111111111111111111111111111111111112",
"pullerWalletId": "privy_wallet_123",
"pullerAddress": "So11111111111111111111111111111111111111112",
"metadataUri": "example",
"status": "active",
"createdBy": "example",
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
},
"meta": {
"requestId": "req_example",
"timestamp": "2025-01-01T00:00:00.000Z"
}
}Error responses use the standard error shape.