Skip to main content
Cresora Commerce
Integration Guides

Tokenization & Saved Cards

How a card becomes a reusable Cresora vault token on the hosted page, and how to charge it server-side.

Cards are captured on the Cresora hosted payment page (HPP) and nowhere else. You create an HPP session with tokenize: true, the payer enters the card on the hosted page and consents to saving it, and the hpp_session.completed webhook delivers a Cresora vault token — an opaque reference with the prefix cvt_. Your server stores that token and charges it later through POST /api/v1/transactions. Raw gateway tokens are never delivered, and raw PAN is never accepted at the transaction boundary.

⚠Warning

There is no client-side tokenization SDK and no direct card-tokenize API. If you are reading older documentation that describes a browser JavaScript library for collecting card data, that product does not exist — the hosted page is the only card-capture surface.

Save a card

Both flows are HPP sessions created with tokenize: true. See the HPP guide for the full session contract.

Charge and save in one flow — page_purpose: "payment":

curl
curl -X POST https://api.cresoracommerce.ai/api/v1/hpp/sessions \
  -H "Authorization: Bearer csk_ab12cd34_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: idem_$(uuidgen)" \
  -d '{
    "merchant_id": "0190a1b2-c3d4-7e5f-8901-23456789abcd",
    "amount": "50.00",
    "currency": "USD",
    "tokenize": true
  }'

Save without charging — page_purpose: "save_card" runs a $0 verification and vaults the card. Omit amount, or send "0.00":

curl
curl -X POST https://api.cresoracommerce.ai/api/v1/hpp/sessions \
  -H "Authorization: Bearer csk_ab12cd34_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: idem_$(uuidgen)" \
  -d '{
    "merchant_id": "0190a1b2-c3d4-7e5f-8901-23456789abcd",
    "tokenize": true,
    "page_purpose": "save_card",
    "credential_usages": ["unscheduled_cof"]
  }'
🔒Compliance

Because the payer enters card data on Cresora-served pages, that data never transits your systems. Which PCI validation requirement applies to your business is a question for your QSA or compliance advisor — this page does not determine your SAQ eligibility.

Receive the token

The vault token arrives on the hpp_session.completed webhook:

{
  "envelope_version": 1,
  "event_type": "hpp_session.completed",
  "data": {}
}

The elided data object carries the token as data.cresoraVaultToken — for example cvt_01885fec-4444-7a31-9bbb-3e5b9a1f8c42. Treat it as opaque; its only use is as vault_token on a later charge.

ℹNote

stored_credential.vaulted fires only when a new credential is vaulted for the first time. Use hpp_session.completed as the per-save signal — it carries the vault token every time, whether or not the credential was newly created.

Charge the saved card

curl
curl -X POST https://api.cresoracommerce.ai/api/v1/transactions \
  -H "Authorization: Bearer csk_ab12cd34_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: idem_$(uuidgen)" \
  -d '{
    "type": "SALE",
    "merchant_id": "0190a1b2-c3d4-7e5f-8901-23456789abcd",
    "amount": "50.00",
    "vault_token": "cvt_01885fec-4444-7a31-9bbb-3e5b9a1f8c42",
    "use_type": "ONE_TIME_FUTURE"
  }'

amount, vault_token, and use_type are required, alongside merchant_id and type. Amounts are decimal strings. A card object at this boundary is rejected with 400.

use_type declares who initiated the charge, and that changes how it is priced:

use_typeInitiated byBehavior
ONE_TIME_FUTURECardholder — customer present, paying with their saved cardSurcharge and convenience fee computed server-side; merchant AVS policy applied
RECURRINGMerchantBilled as-is — no fees, no AVS policy
INSTALLMENTMerchantBilled as-is — no fees, no AVS policy
UNSCHEDULED_COFMerchantBilled as-is — no fees, no AVS policy

Scope is set at save time through credential_usages on the HPP session, using the lowercase forms recurring, installment, unscheduled_cof, and one_time_future. Every charge then declares a use_type, and that intent must sit inside the scope the credential was saved with. Charging outside it returns 422 stored_credential_scope_violation.

A credential is one consent, not one save:

  • Re-saving the same card under the same consent returns the same id and the same vault_token — the token is stable across re-saves — and fires no stored_credential.vaulted.
  • Saving the same card with a different scope creates a separate entry.
  • Revocation is final. A revoked token is never reissued.
💡Tip

Two entries for the same card can share the same card.last4, so last4 alone cannot tell them apart. Key your own records on id or vault_token.

Manage credentials

These endpoints require the stored_credential:read, stored_credential:revoke, and stored_credential:charge permission scopes.

List credentials for a merchant — optionally narrowed to one customer_id, with cursor and page_size for pagination:

curl
curl https://api.cresoracommerce.ai/api/v1/merchants/0190a1b2-c3d4-7e5f-8901-23456789abcd/stored-credentials \
  -H "Authorization: Bearer csk_ab12cd34_xxxxxxxxxxxxxxxxxxxxxxxx"

The response is { "data": [...], "pagination": {...} }. Fetch one entry with GET /api/v1/merchants/{merchantId}/stored-credentials/{storedCredentialId}.

Each StoredCredential always carries id, vault_token, merchant_id, partner_id, rail, card (including last4), scope, enrollment_terms, consent_captured, state, created_at, and version. customer_id and processor are optional. scope is an array of RECURRING, INSTALLMENT, UNSCHEDULED_COF, or ONE_TIME_FUTURE and may be empty. state is one of ACTIVE, REVOKED, or EXPIRED. consent_captured is a boolean — the underlying gateway consent identifier stays backend-only and is never returned.

Revoke a credential. reason is optional, capped at 500 characters, and recorded in the audit trail. The response is 204, the state moves ACTIVE → REVOKED, and the vault token can no longer be charged:

curl
curl -X DELETE "https://api.cresoracommerce.ai/api/v1/merchants/0190a1b2-c3d4-7e5f-8901-23456789abcd/stored-credentials/019e91c2-1f08-7a55-b3d1-88e0c4a72f61?reason=customer%20request" \
  -H "Authorization: Bearer csk_ab12cd34_xxxxxxxxxxxxxxxxxxxxxxxx"

No Idempotency-Key is required — DELETE is idempotent per RFC 9110.

Errors

CodeHTTPWhat it means
stored_credential_scope_violation422The use_type falls outside the scope the credential was saved with. Charge within scope, or have the payer save the card again with the usage you need.
stored_credential_not_chargeable422A legacy entry that cannot be charged. Not retryable — the payer must re-establish the card through a save-card flow.
raw_card_not_supported400A card object was sent to POST /api/v1/transactions. Raw PAN is never accepted; capture the card on the hosted page instead.