Skip to main content

Savings

Create automated savings plans for your customers. Supports contributions, withdrawals, and full lifecycle management.


List Savings Plans

GET /savings/plans/

Retrieve all savings plans for your integration. Results are paginated.

Headers

FieldValue
AuthorizationBearer PAYSCRIBE_API_KEY

Query Parameters

FieldTypeRequiredDescription
pageintegerNoPage number to fetch. Defaults to 1.
per_pageintegerNoNumber of plans per page. Defaults to 20.
customer_idstringNoFilter by customer identifier.
statusstringNoFilter by plan status (active, paused, cancelled, completed, failed).
currencystringNoFilter by NGN or USD.
qstringNoSearch plan title or customer name.

Request

curl -X GET "https://sandbox.payscribe.ng/api/v1/savings/plans/?page=1&per_page=20" \
-H "Authorization: Bearer $PAYSCRIBE_API_KEY"

Response

Status: 200 OK
{
"status": true,
"description": "Savings plans fetched.",
"message": {
"details": {
"plans": [{
"id": "svp_abc123",
"title": "Emergency fund",
"type": "fixed",
"currency": "NGN",
"status": "active",
"contribution_amount": 10000,
"frequency": "monthly",
"balance": 140000,
"available_balance": 140000,
"total_contributed": 140000,
"total_withdrawn": 0,
"next_run_at": "2026-09-01 09:00:00",
"created_at": "2026-08-01 09:00:00",
"customer": {"id": "cus_xyz456", "name": "John Doe", "email": "customer@example.com"}
}],
"total": 1,
"page": 1,
"per_page": 20
}
},
"status_code": 200
}

Create Savings Plan

POST /savings/plans/

Create a new automated savings plan for a customer.

Headers

FieldValue
AuthorizationBearer PAYSCRIBE_API_KEY
Content-Typeapplication/json

Body Parameters

FieldTypeRequiredDescription
customer_idstringYesCustomer identifier.
currencystringYesNGN or USD.
typestringYestarget or fixed. A target plan also needs target_amount or target_date.
titlestringYesHuman-readable plan title (maximum 100 characters).
contribution_amountnumberYesAmount per contribution.
frequencystringYesContribution frequency. One of daily, weekly, monthly.
start_atstringYesStart date and time, for example 2026-09-01 09:00:00.
timezonestringNoIANA timezone; defaults to UTC.
lock_typestringNoflexible (default) or locked.
missed_policystringNoretry_until_success (default), skip_and_continue, or pause_on_failure.
target_amountnumberConditionalTarget savings amount. Required for a target plan if target_date is omitted. Ignored for fixed plans.
target_datestringConditionalTarget date (YYYY-MM-DD). Required for a target plan if target_amount is omitted. Ignored for fixed plans.
early_withdrawal_penalty_bpsintegerNoPenalty in basis points applied to a withdrawal made before maturity. Only used when lock_type is locked.
retry_maxintegerNoMax retries for a failed contribution charge (0-20, default 3).
retry_interval_minutesintegerNoMinutes between retries (5-10080, default 1440).

Request

curl -X POST "https://sandbox.payscribe.ng/api/v1/savings/plans/" \
-H "Authorization: Bearer $PAYSCRIBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_xyz456",
"currency": "NGN",
"type": "fixed",
"title": "Emergency fund",
"contribution_amount": 10000,
"frequency": "monthly",
"timezone": "Africa/Lagos",
"start_at": "2026-09-01 09:00:00"
}'

Response

Status: 200 OK
{
"status": true,
"description": "Savings plan created.",
"message": {
"details": {
"id": 123,
"saving_id": "svp_abc123",
"title": "Emergency fund",
"type": "fixed",
"currency": "NGN",
"frequency": "monthly",
"status": "active",
"next_run_at": "2026-09-01 09:00:00",
"customer": {"id": "cus_xyz456", "name": "John Doe", "email": "customer@example.com"}
}
},
"status_code": 200
}

Get Savings Plan

GET /savings/plans/{id}

Retrieve the details of a single savings plan.

Headers

FieldValue
AuthorizationBearer PAYSCRIBE_API_KEY

Path Parameters

FieldTypeRequiredDescription
idstringYesThe savings plan ID to retrieve.

Request

curl -X GET "https://sandbox.payscribe.ng/api/v1/savings/plans/svp_abc123" \
-H "Authorization: Bearer $PAYSCRIBE_API_KEY"

Response

Status: 200 OK
{
"status": true,
"description": "Savings plan fetched.",
"message": {
"details": {
"saving_id": "svp_abc123",
"title": "Emergency fund",
"type": "fixed",
"currency": "NGN",
"status": "active",
"contribution_amount": 10000,
"frequency": "monthly",
"timezone": "Africa/Lagos",
"lock_type": "flexible",
"balance": 140000,
"locked_balance": 0,
"available_balance": 140000,
"total_contributed": 140000,
"total_withdrawn": 0,
"target_amount": null,
"target_date": null,
"start_at": "2026-09-01 09:00:00",
"next_run_at": "2026-10-01 09:00:00",
"missed_policy": "retry_until_success",
"early_withdrawal_penalty_bps": null,
"created_at": "2026-08-01 09:00:00",
"updated_at": "2026-09-01 09:00:00",
"customer": {"id": "cus_xyz456", "name": "John Doe", "email": "customer@example.com", "phone": "+2348012345678"}
}
},
"status_code": 200
}

List Savings Plan Transactions

GET /savings/plans/{id}/transactions

Retrieve the contribution and withdrawal history for a single savings plan. Results are paginated.

Headers

FieldValue
AuthorizationBearer PAYSCRIBE_API_KEY

Path Parameters

FieldTypeRequiredDescription
idstringYesThe savings plan ID.

Query Parameters

FieldTypeRequiredDescription
pageintegerNoPage number to fetch. Defaults to 1.
page_sizeintegerNoRecords per page (1-100). Defaults to 25.
statusstringNoFilter by success, failed, or pending.
fromstringNoStart date (YYYY-MM-DD), inclusive.
tostringNoEnd date (YYYY-MM-DD), inclusive.
curl -X GET "https://sandbox.payscribe.ng/api/v1/savings/plans/svp_abc123/transactions?page=1&page_size=25" \
-H "Authorization: Bearer $PAYSCRIBE_API_KEY"

Response

Status: 200 OK
{
"status": true,
"description": "Savings plan transactions fetched.",
"message": {
"details": {
"saving_id": "svp_abc123",
"plan_id": 42,
"transactions": [{
"id": 0,
"trans_id": "TRX-20260901-0001",
"description": "Monthly contribution",
"amount": 10000,
"currency": "NGN",
"fee": 0,
"status": "success",
"created_at": "2026-09-01 09:00:05",
"meta": null
}],
"total": 1,
"page": 1,
"per_page": 25
}
},
"status_code": 200
}
Known issue

transactions[].id is currently always 0 (the endpoint selects the wrong column internally). Use trans_id to identify a transaction until this is fixed server-side.


Pause Savings Plan

POST /savings/plans/{id}/pause

Pause an active savings plan. Contributions will stop until the plan is resumed.

Headers

FieldValue
AuthorizationBearer PAYSCRIBE_API_KEY

Path Parameters

FieldTypeRequiredDescription
idstringYesThe savings plan ID to pause.

Request

curl -X POST "https://sandbox.payscribe.ng/api/v1/savings/plans/svp_abc123/pause" \
-H "Authorization: Bearer $PAYSCRIBE_API_KEY"

Response

Status: 200 OK
{
"status": true,
"description": "Savings plan paused.",
"message": {"details": []},
"status_code": 200
}

Resume Savings Plan

POST /savings/plans/{id}/resume

Resume a paused savings plan. Contributions will restart on the next scheduled cycle.

Headers

FieldValue
AuthorizationBearer PAYSCRIBE_API_KEY

Path Parameters

FieldTypeRequiredDescription
idstringYesThe savings plan ID to resume.

Request

curl -X POST "https://sandbox.payscribe.ng/api/v1/savings/plans/svp_abc123/resume" \
-H "Authorization: Bearer $PAYSCRIBE_API_KEY"

Response

Status: 200 OK
{
"status": true,
"description": "Savings plan resumed.",
"message": {"details": []},
"status_code": 200
}

Cancel Savings Plan

POST /savings/plans/{id}/cancel

Cancel an active or paused savings plan. The plan cannot be reactivated after cancellation. Remaining balance is available for withdrawal.

Headers

FieldValue
AuthorizationBearer PAYSCRIBE_API_KEY

Path Parameters

FieldTypeRequiredDescription
idstringYesThe savings plan ID to cancel.

Request

curl -X POST "https://sandbox.payscribe.ng/api/v1/savings/plans/svp_abc123/cancel" \
-H "Authorization: Bearer $PAYSCRIBE_API_KEY"

Response

Status: 200 OK
{
"status": true,
"description": "Savings plan cancelled.",
"message": {"details": []},
"status_code": 200
}

Withdraw from Savings Plan

POST /savings/plans/{id}/withdraw

Withdraw funds from an active or cancelled savings plan. Withdrawals are processed instantly to the customer's wallet.

Headers

FieldValue
AuthorizationBearer PAYSCRIBE_API_KEY
Content-Typeapplication/json

Path Parameters

FieldTypeRequiredDescription
idstringYesThe savings plan ID to withdraw from.

Body Parameters

FieldTypeRequiredDescription
amountnumberYesAmount to withdraw, in the plan's currency major unit (naira for NGN, dollars for USD). Must not exceed available_balance.
refstringNoIdempotency reference. A random one is generated if omitted.

Unlike other write endpoints, reusing ref here is a genuine idempotent replay: if the original withdrawal already succeeded, the same withdrawal_id is returned again with status_code: 200 instead of an error. Reusing a ref whose withdrawal is still pending or failed returns 400 Duplicate request.

Request

curl -X POST "https://sandbox.payscribe.ng/api/v1/savings/plans/svp_abc123/withdraw" \
-H "Authorization: Bearer $PAYSCRIBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"amount": 25000, "ref": "WD-20260828-001"}'

Response

Status: 200 OK
{
"status": true,
"description": "Withdrawal successful.",
"message": {
"details": {
"withdrawal_id": "swd_xyz789",
"amount": 25000,
"currency": "NGN",
"ledger_ref": "PS_WD_ABC123XYZ",
"ref": "WD-20260828-001"
}
},
"status_code": 200
}

Webhooks

EventDescription
savings.plans.createdA savings plan was created
savings.plans.pausedSent whenever a plan's status changes via pause, resume, or cancel — check the status field in the payload (paused, active, or cancelled) to tell them apart
savings.contribution.successContribution collected successfully
savings.contribution.failedContribution failed
savings.withdrawal.successWithdrawal processed
savings.withdrawal.failedWithdrawal failed
Known issue

Resuming or cancelling a plan currently dispatches savings.plans.paused (not savings.plans.resumed or savings.plans.cancelled) — a naming bug in the current release. Read the status field in the payload rather than relying on the event name to distinguish these three transitions.

See Webhooks for payload format and verification.

Was this page helpful?

Report a docs issue →