Save a payment method without charging it

Stores a card, bank account or wallet against an account as a saved payment method, tokenised at the gateway, without taking a payment. Support staff use it from the account screen to put a customer's new card on file over the phone; customers use it from the hosted checkout when a checkout request asks for a method to be saved, and integrators call the API directly. The same call can name contracts the new method should be attached to, and can register a token the integrator already holds at the gateway.

Where you can do this

  • Merchant View: Account (Add Payment Method)
  • Merchant View: Account header (Add Payment Method)
  • The hosted checkout: Payment form (Confirm (confirm page, TOKENISE); the gateway's own save-card page (hosted))
  • API: Create a checkout (POST /checkouts) — action TOKENISE for an account; prepares the checkout, the save itself is the POST below
  • The hosted checkout: the hosted checkout submits in TOKENISE mode; the hosted checkout forwards it to POST /c/api/payment_methods
  • API: Create a payment method (POST /payment_methods) — body carries card, bank or wallet details, or the id of a saved method; with token it registers a token already held at the gateway without calling it
  • Automatically (Shuttle): gateway return for a redirect-based method — the provider's connector receives the customer's return or webhook and posts the token to Shuttle, which activates the method and attaches any contracts parked on it

Before you start

  • An account, named by id or CRM key, or account details from which one can be registered or created anonymously (the channel must allow that).
  • A gateway that can save cards or create tokens for the card type, either named in the call or reachable through the initiative's routing for the account's country.
  • For a saved method named by id, that method must be ACTIVE or FAILING.
  • For a token registered directly, the gateway must exist and the token must be supplied.

Inputs

Fields on POST /c/api/payment_methods, inside payment_method:

InputRequiredMeaning and constraints
accountyesAn account id, or an object: id, or crm_key (alias alt_key) with first_name, last_name, company, email, phone, address (country, line1 to line6) and tags. With crm_key and no id the most recently created account with that CRM key is used, or one is registered through the channel. With neither, an anonymous account is created from the details
idnoA saved payment method to reuse; nothing new is stored or tokenised, the call only attaches it to contracts
gatewayconditionalRequired with token. Otherwise optional: when omitted the gateway is chosen by routing (initiative, the account's country, card type)
currencynoPassed to the gateway with the tokenisation
codenoReporting code for the method; must not be in use by an ACTIVE or FAILING method
noncenoSerialises concurrent calls carrying the same value and is stored on the method. A payment-link nonce (pl_...) marks that link complete once the method is ACTIVE
typenoCard type (alias card_type). Derived from card_number when omitted; SEPA, ACH or BACS is inferred from the bank fields
card_numberconditionalOne of a card, bank or wallet detail set is needed for a new method. Non-digits are stripped
card_expirynoAlias expiry. Accepts MMYY, MM/YY, M/YY or MYY and is stored as a month; other formats are not stored
card_cvcnoPassed to the gateway, never stored
last4noAlias card_ending
binnoAlias card_bin
requires_cvcnoMarks the saved method as needing a CVC on later use
ibanconditionalAlias sepa_iban; makes the method SEPA
account_holder_namenoAliases cardholder_name, card_holder_name, sepa_account_holder_name, ach_account_holder_name
account_typeconditionalAlias ach_account_type; makes the method ACH
routing_numbernoAlias ach_routing_number
account_numberconditionalAlias ach_account_number; makes the method BACS when no other type applies
namenoAlias description. Stored as the method's description, localised with the card type and ending
addressnoAlias billing. Billing address (country, line1 to line6) sent to the gateway and stored
tagsnoStored on the method
metadatanoStored on the method
sourcenoecommerce (default), moto, pos or recurring; sets whether the customer and staff are present, which the gateway is told and the method records
success_urlnoWhere a redirect-based method returns on success; #PAYMENTMETHODKEY# is replaced and payment_method=pm_... appended
cancel_urlnoAs success_url, for a cancelled or failed authorisation
localenoAs user_agent
tokenconditionalA token already held at the gateway. Switches the call to registration: no gateway call is made and the method is stored with status (default ACTIVE), sub_status and sub_status_reason as sent
manualnoSame effect as sending token
contracts[]noContracts to attach the method to; see Change the payment method on a contract

Fields on POST /c/api/checkout for this function: action TOKENISE (required), force_add (hides the account's saved methods so a new one must be entered; Merchant View always sets it), legal_entity (narrows the gateways the form offers), and the checkout fields that belong to Take a one-off payment (nonce, account, channel, source, currency) and to Change the payment method on a contract (contracts[]).

Rules

Checked by the API means Shuttle refuses the request however it is sent; a screen name means only that screen refuses it, and a direct API call would be accepted.

RuleChecked byWhat you see
The checkout call follows the checkout rules of Take a one-off payment (body, nonce, CRM key without spaces, duplicate nonce)The APIsee Take a one-off payment
An account is requiredThe APIVALIDATION_ERROR: "Missing account"
A token registered directly needs a gatewayThe APIVALIDATION_ERROR: "Missing gateway"
A CRM key must not contain spacesThe APIVALIDATION_ERROR: "crm_key cannot inlcude spaces" (sic)
A customer's account session may only save a method on its own account; the check is on the account, whether given by id or resolved from crm_keyThe APINO_PERMISSION: "No permissions"; Shuttle: INVALID (BOLT-1005)
An account object with neither id nor crm_key creates an anonymous account, which the channel must allowThe APIINVALID (BOLT-1086, anonymous accounts disabled)
An account named by crm_key that the CRM does not know is refused unless the channel allows registrationThe APIINVALID (BOLT-1031 with registration on, BOLT-1087 with it off)
The account must resolve; when creating one fails for any reason other than fraud the failure is swallowed and the call fails on the missing accountThe APIINVALID (BOLT-1031)
A merged account resolves to the account it was merged into; the method is stored thereThe APIsilent (see Link a duplicate account)
Every call creates a customer session for the account and runs the fraud screening on it; a blocked session refuses the call with the screening's reasonThe APIINVALID (BOLT-1088) with the fraud reason as the message
The channel must exist and accept paymentsThe APIINVALID: "Invalid value for field channelKey." / channel not accepting payments
A saved method named by id must exist and be ACTIVE or FAILING. It is attached to contracts only when ACTIVE; a FAILING method returns OK and changes nothingThe APINOT_FOUND on "payment_method " / INVALID on "payment_method"
Each contract in contracts[] must exist and be in a status that accepts a new method; the set and the attach rules are on Change the payment method on a contractThe APIINVALID on "contract: "
code must not be in use by an ACTIVE or FAILING methodThe APIINVALID: "Invalid code"
The card type is derived from the card number when not sent; a number whose type cannot be recognised is refusedThe APIINVALID (BOLT-1093)
A card expiry of December in the current year, or on the test card ending 1111, is not stored (test-card convention)The APIsilent; the method shows no expiry
A named gateway must exist and have a payment processor; when none is named, the initiative's routing for the account's country and the card type must reach one. A legal_entity in the body plays no part in this routing, and no part in anything else: it is dropped on the way inThe APIINVALID (BOLT-1095 named gateway; BOLT-1105 no route)
The gateway must offer card saving or token creation for the card type; checked only when a card type is known, so a call with no recognisable type skips itThe APIINVALID (BOLT-1096, tokenisation not available)
The gateway call itself failing (a connector error rather than a decline) abandons the call; nothing is storedThe APIINVALID (BOLT-1167) with the gateway's messages
A gateway decline is not an error: the method is stored INACTIVE with the gateway's reason in gateway_status and the call returns OK. Callers must read status; the hosted checkout does and shows the reasonThe API and the hosted checkoutOK with status INACTIVE
Only one call per nonce runs at a time (a random one when none is sent); a second call with the same nonce while the first runs fails at once rather than waitingThe APIINVALID (BOLT-7059)
The nonce does not stop duplicates: once the first call completes, a second call with the same nonce and details stores a second method. Only a payment carries a duplicate-nonce rule (see Take a one-off payment)The APIsilent; two methods
From the hosted checkout, calls that reuse the same saved method id are serialised for 60 seconds and a second call within 5 seconds receives the first call's result; a new-card submission is keyed by the clock, so nothing serialises it beyond the nonce rule aboveThe APIsecond call waits, or gets the first result
the hosted checkout offers a gateway for saving only when it can save cards or create tokens for the card type, the currency matches, the gateway is not running down and its routing rules allow the card; a currency whose maximum amount rule is zero is treated as disabled for savingThe hosted checkoutgateway or currency not offered
Registering a token directly: the gateway must exist, token is mandatory, code must be unique, and the session needs account on the accountThe APINOT_FOUND on "payment_gateway " / MANDATORY on "token" / INVALID: "Invalid code" / NO_PERMISSION
Merchant View offers Add Payment Method only when the account's division has a WEB channel; the server has no such ruleMerchant View screencontrol hidden

What happens

  • A new saved method appears on the account and in the response, with status ACTIVE (ready to use; sub_status PENDING where a mandate is still being set up), REQAUTH with an authorisation_url the customer must complete, or INACTIVE with the gateway's reason in gateway_status. Nothing is charged.
  • Where contracts[] was sent, those contracts switch to the new method as soon as it is ACTIVE (at once, or when the customer completes the authorisation) and any outstanding amount is collected straight away; see Change the payment method on a contract. the hosted checkout warns the customer of that before they confirm.
  • Webhook subscribers receive PAYMENT_METHOD.CREATED, then PAYMENT_METHOD.ACTIVE, PAYMENT_METHOD.PENDING or PAYMENT_METHOD.FAILED, and CONTRACT.UPDATE for each contract attached; a redirect-based method raises PAYMENT_METHOD.UPDATE and PAYMENT_METHOD.ACTIVE when it completes.
  • An account named by CRM key that Shuttle did not know is registered; details sent with an existing account update its CRM record; an anonymous account is created when neither id nor CRM key is sent. In Merchant View the account screen reloads its saved methods when the checkout reports success.
  • A payment link whose nonce was used is marked complete with the method.
  • No email or SMS is sent by the tokenisation itself.

Who can do this

  • Roles: Admin only today; intended for Support as well, and being aligned. Support holds account but Merchant View gates the control on payment_contract. From the hosted checkout, no operator role applies.
  • Admin app: the moto_tokenise dashboard option, a WEB channel on the division, and a legal entity chosen when the division has more than one active; applies to the admin entry points only.
  • Checkout form: force_add hides saved methods; a gateway feature can skip the confirm step; the save-card toggle is hidden in tokenise mode because saving is the point of the request.

Related


Did this page help you?