Skip to content

Close Card

Submits an irreversible close (cancellation) request for an active virtual card. The call is accepted synchronously — the card immediately enters status=4 (closing) — while the actual closure and the balance refund complete asynchronously via webhook + platform review.

  • Only cards owned by the current AppID account and of a virtual card type are accepted.
  • Only status=2 (active) cards can be closed; a frozen(6) card must be unfrozen first.
  • The remaining card balance is refunded to your wallet after platform review, per the card package's close-fee rules — the refund is not instant.

Endpoint

ItemValue
MethodPOST
Path/api/v1/openapi/card/close
AuthHMAC
IdempotencyNot required

No Idempotency-Key needed

Close is protected by the card state machine: retrying returns 400 card_is_closing (in progress) or 400 card_already_closed (done) rather than double-applying. The submission itself moves no money.

Request Fields

FieldTypeRequiredDescription
card_idstringcard_<id> — must belong to your account and be a virtual card

Example Request

json
{ "card_id": "card_12345" }

Response Fields

FieldTypeDescription
card_idstringEcho of the card ID
statusintCard status after acceptance — always 4 (closing) on success
status_descstringEnglish status description — closing
successbooltrue when the close request was accepted
messagestringHuman-readable acceptance note

Example Response

json
{
  "code": 200,
  "message": "OK",
  "data": {
    "card_id": "card_12345",
    "status": 4,
    "status_desc": "closing",
    "success": true,
    "message": "close request accepted"
  }
}

Lifecycle after acceptance

  1. Acceptance — this call returns status=4 (closing); the card can no longer be used for payments.
  2. Provider closure — the upstream provider confirms the closure asynchronously; you receive the card.closed webhook and /card/info starts reporting status=5 (closed).
  3. Refund review — the remaining balance (minus the package's close fee) enters the platform's refund review; once approved it is credited to your wallet. Rejection restores the card to active — monitor card.status_changed.

Preconditions & Rules

  1. Ownershipcard_id must belong to the authenticated account, else 404 card_not_found.
  2. Card type — only virtual cards (virtual_l / virtual_p / virtual_v / virtual_r / virtual_g / virtual_a).
  3. State — only status=2 (active); frozen(6) must be unfrozen first (card_frozen_cannot_close); repeat calls hit card_is_closing / card_already_closed.
  4. Irreversible — once accepted the closure cannot be cancelled by you.

Common Errors

HTTPmessage_keyDescription
400openapi_invalid_card_idMissing/invalid card_id
400openapi_card_type_not_supportedCard is not a virtual card type
400card_is_closingA close request is already in progress
400card_already_closedCard is already closed
400card_frozen_cannot_closeCard is frozen — unfreeze first
400card_status_cannot_closeCard is not active; cannot be closed
400close_not_accepted_by_upstreamProvider did not accept the closure; the card has been restored to active — retry later
400card_upstream_closed_pending_reconcileCard was already closed directly by the provider and awaits manual refund reconciliation — do not close here
400card_config_not_found / card_type_mismatch / operation_not_supportedConfiguration / card-type problems
401openapi_invalid_credentialsAuth failure
404card_not_foundCard not found / not owned
500openapi_close_card_failedServer error

Integration pitfalls & best practices

Read before integrating

Close is the highest-consequence card operation: irreversible, provider-bound, and money moves later via review.

  1. Synchronous, provider-bound call — allow up to ~60 s. The submission calls the upstream provider inline. Set your HTTP client timeout to ≥ 60 s for this endpoint.
  2. A client-side timeout does NOT mean the close failed. On any timeout / network error, reconcile via /card/info: status=4/5 → accepted (do not resubmit as a "new" close); status=2 → not applied (safe to retry).
  3. Completion signal is asynchronous. Treat the card.closed webhook (or polling until status=5) as completion — the synchronous response only means "accepted".
  4. Refund is not instant and not guaranteed to equal the last seen balance. It passes platform review and deducts the package close fee; a rejected review restores the card to active. Reconcile your books against the wallet credit, not against the pre-close card balance.
  5. close_not_accepted_by_upstream auto-rolls back. The card is already restored to active when you receive this error — no cleanup needed on your side, just retry later.
  6. Treat card_is_closing / card_already_closed as "already in the desired state", not hard errors, when retrying.

Released under MIT-equivalent terms.