Terminate a card
curl --request POST \
--url https://sandbox-api.sakawave.example/v1/cards/{cardId}/terminate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"externalReference": "card_terminate_20260814_001",
"destinationAccountId": "01K2Z3AB4D5E6F7G8H9JKMNPQR"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
externalReference: 'card_terminate_20260814_001',
destinationAccountId: '01K2Z3AB4D5E6F7G8H9JKMNPQR'
})
};
fetch('https://sandbox-api.sakawave.example/v1/cards/{cardId}/terminate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://sandbox-api.sakawave.example/v1/cards/{cardId}/terminate"
payload = {
"externalReference": "card_terminate_20260814_001",
"destinationAccountId": "01K2Z3AB4D5E6F7G8H9JKMNPQR"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "01K2Z3AB4R5S6T7V8WXYZABCDE",
"cardId": "01K2Z3AB4S5T6V7W8XYZABCDEF",
"type": "termination",
"status": "pending",
"sourceCurrency": "USD",
"destinationCurrency": "USD",
"sourceAmount": "5000",
"destinationAmount": "5000",
"failureCode": null,
"failureReason": null,
"completedAt": null,
"createdAt": "2026-08-14T09:11:40.000Z",
"updatedAt": "2026-08-14T09:12:00.000Z"
}{
"statusCode": 400,
"message": "Must be a valid identifier.",
"code": "validation_failed",
"errors": [
{
"message": "Must be a valid identifier.",
"field": "accountId",
"code": "custom",
"path": [
"accountId"
]
}
]
}{
"statusCode": 401,
"code": "INVALID_API_KEY",
"message": "Invalid or inactive API credentials."
}{
"statusCode": 403,
"message": "International wallets for your customers are not available yet. Your own approval cannot be used for a customer wallet.",
"code": "international_customer_wallet_not_supported",
"currency": "USD"
}{
"statusCode": 404,
"code": "resource_not_found",
"message": "Resource not found."
}{
"statusCode": 409,
"code": "resource_conflict",
"message": "The request conflicts with the current resource state."
}{
"statusCode": 429,
"message": "Too many API requests. Try again later.",
"code": "api_key_rate_limit_exceeded",
"retryAfterSeconds": 17
}{
"statusCode": 500,
"code": "internal_server_error",
"message": "An unexpected error occurred."
}{
"statusCode": 503,
"code": "provider_unavailable",
"message": "We could not issue an account number just now. Try again shortly."
}Cards
Terminate a card
Ends the card permanently and sweeps its remaining balance. The card is frozen first, moves to terminating, and reaches terminated once the sweep settles.
POST
/
v1
/
cards
/
{cardId}
/
terminate
Terminate a card
curl --request POST \
--url https://sandbox-api.sakawave.example/v1/cards/{cardId}/terminate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"externalReference": "card_terminate_20260814_001",
"destinationAccountId": "01K2Z3AB4D5E6F7G8H9JKMNPQR"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
externalReference: 'card_terminate_20260814_001',
destinationAccountId: '01K2Z3AB4D5E6F7G8H9JKMNPQR'
})
};
fetch('https://sandbox-api.sakawave.example/v1/cards/{cardId}/terminate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://sandbox-api.sakawave.example/v1/cards/{cardId}/terminate"
payload = {
"externalReference": "card_terminate_20260814_001",
"destinationAccountId": "01K2Z3AB4D5E6F7G8H9JKMNPQR"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "01K2Z3AB4R5S6T7V8WXYZABCDE",
"cardId": "01K2Z3AB4S5T6V7W8XYZABCDEF",
"type": "termination",
"status": "pending",
"sourceCurrency": "USD",
"destinationCurrency": "USD",
"sourceAmount": "5000",
"destinationAmount": "5000",
"failureCode": null,
"failureReason": null,
"completedAt": null,
"createdAt": "2026-08-14T09:11:40.000Z",
"updatedAt": "2026-08-14T09:12:00.000Z"
}{
"statusCode": 400,
"message": "Must be a valid identifier.",
"code": "validation_failed",
"errors": [
{
"message": "Must be a valid identifier.",
"field": "accountId",
"code": "custom",
"path": [
"accountId"
]
}
]
}{
"statusCode": 401,
"code": "INVALID_API_KEY",
"message": "Invalid or inactive API credentials."
}{
"statusCode": 403,
"message": "International wallets for your customers are not available yet. Your own approval cannot be used for a customer wallet.",
"code": "international_customer_wallet_not_supported",
"currency": "USD"
}{
"statusCode": 404,
"code": "resource_not_found",
"message": "Resource not found."
}{
"statusCode": 409,
"code": "resource_conflict",
"message": "The request conflicts with the current resource state."
}{
"statusCode": 429,
"message": "Too many API requests. Try again later.",
"code": "api_key_rate_limit_exceeded",
"retryAfterSeconds": 17
}{
"statusCode": 500,
"code": "internal_server_error",
"message": "An unexpected error occurred."
}{
"statusCode": 503,
"code": "provider_unavailable",
"message": "We could not issue an account number just now. Try again shortly."
}Termination is irreversible. There is no way to reopen a terminated card, and the PAN cannot be recovered.
The balance
Whatever is left sweeps todestinationAccountId, or to the card’s own settlement account when you do not name one. The named account must be one of yours and able to receive.
If the card is still holding an authorisation, the operation comes back pending and completes once the hold clears — termination waits rather than stranding the money.
Error codes
| Status | code | Cause |
|---|---|---|
400 | validation_failed | A field failed validation. |
403 | card_client_account_required | The destination account is a customer wallet. |
409 | card_terminal | The card is already used, terminating, terminated, failed, or marked fraud. |
409 | card_account_ineligible | The destination account is missing, inactive, or cannot be credited. |
503 | card_provider_unavailable | The card provider could not be reached. |
401 | INVALID_API_KEY | The key is missing, invalid, inactive, expired, from the other environment, or blocked by its IP allowlist. |
404 | card_not_found | No such card for this business. |
429 | api_key_rate_limit_exceeded | The per-minute limit for this key was exceeded. |
Authorizations
A secret API key, sent as Authorization: Bearer sk_test_… in sandbox or Bearer sk_live_… in live.
Path Parameters
Card ULID. A 26-character ULID.
Required string length:
26Pattern:
^[0-7][0-9A-HJKMNP-TV-Z]{25}$Example:
"01K2Z3AB4C5D6E7F8G9HJKMNPQ"
Body
application/json
Response
Successful response.
A 26-character ULID.
Required string length:
26Pattern:
^[0-7][0-9A-HJKMNP-TV-Z]{25}$Example:
"01K2Z3AB4C5D6E7F8G9HJKMNPQ"
A 26-character ULID.
Required string length:
26Pattern:
^[0-7][0-9A-HJKMNP-TV-Z]{25}$Example:
"01K2Z3AB4C5D6E7F8G9HJKMNPQ"
Available options:
issuance, funding, withdrawal, termination Available options:
created, submitting, pending, completed, failed Available options:
NGN, USD, GBP, EUR, GHS, ZAR, UGX, CAD, MXN, AED, BTC, ETH, USDT, USDC Available options:
NGN, USD, GBP, EUR, GHS, ZAR, UGX, CAD, MXN, AED, BTC, ETH, USDT, USDC An integer number of the asset’s smallest unit. Use this value for arithmetic.
Pattern:
^-?\d+$Example:
"2500000"
An integer number of the asset’s smallest unit. Use this value for arithmetic.
Pattern:
^-?\d+$Example:
"2500000"
Example:
"2026-08-14T09:00:00.000Z"
Example:
"2026-08-14T09:00:00.000Z"
Example:
"2026-08-14T09:00:00.000Z"