Card Payments
Please note: If you want to move money between a consumer’s Upward DDA and a debit card they hold at another bank, you’re in the right spot.
Overview
Card Payments let a consumer link an external debit card and then move money to or from it in near real time. There are two directions:
Both directions reuse the same registered card, so a consumer links their card once and can then be paid out (OCT) or top up their account (AFT).
The integration has two halves:
- Card registration happens in the browser, inside an Upward embedded component. Card numbers are collected in a PCI-compliant iframe hosted by the card processor, so the PAN never touches your systems or Upward’s.
- Moving money happens server-to-server, from your backend, using a Partner API Token.
The Card Payments flow
Prerequisites
- A Partner API Token with
api:writeandapi:read, used for all server-side calls. Never expose it to the browser. - A Customer Access Token for the consumer, used to load the embedded component. See Token Exchange.
- An onboarded, active consumer with a payment card and a funded DDA.
- A registered webhook endpoint. See Registration.
A consumer must be active to create an OCT or AFT. Requests for an
inactive consumer are rejected with 422 consumer_inactive.
Base URLs
Part 1 — Register the card
Mint a Customer Access Token
Exchange your Partner API Token for a consumer-scoped token. The card-registration component needs these scopes:
See the Token Exchange endpoint, and Scopes for the full matrix.
Customer Access Tokens expire after 1 hour. Mint one immediately before rendering the component rather than reusing a stored token.
Display the card-registration component
The simplest integration is the drop-in component. Point an iframe (or web view) at the external-card route with the consumer’s token:
The component renders the card-entry form, submits it to the card processor, and shows a success screen when the card is saved.
Card entry must happen inside the Upward component. You cannot build your own card-entry screen — collecting card details yourself would put your application inside the PCI boundary, which this integration is designed to avoid.
Displaying the component on your own domain. What you can change is where the component is hosted. Call the iframe endpoint with a domain and the returned URL is issued for that parent domain, so you can surface the flow anywhere you need it.
Requires api:card-management:write on a Customer Access Token, or api:write on a Partner API Token.
The body is optional — omit it entirely to use the domain configured for your partner:
Response:
Render iframe_url in an iframe. It carries a short-lived registration session, so request it when the consumer reaches the card-entry screen rather than ahead of time.
The card-registration template itself is configured by Upward against your partner record. It is not a request parameter and does not need to be supplied.
Listen for the completion message
The embedded component posts messages to the parent window. Listen for them to know when the consumer is finished:
See Component Messaging for the full event list.
Treat the message as a prompt to go check, not as proof of success. Always confirm the card server-side in the next step before moving money.
Confirm the card was saved
From your backend, list the consumer’s external cards:
Requires api:card-management:read on a Customer Access Token, or api:read on a Partner API Token. If you are reading the card from a consumer-facing surface that already holds a profile-scoped token, api:consumer-profile:read is also accepted.
The card does not appear instantly. It is saved when the card processor
confirms the registration, which lands shortly after the consumer finishes
the form. An empty results array immediately after component.closed means
not yet, not failed. Poll every couple of seconds for up to about 30
seconds before surfacing an error.
Before moving money, check three things:
statusisactivepushEnabledistrueif you intend to send an OCTpullEnabledistrueif you intend to send an AFT
Not every debit card supports both directions. A card can be perfectly valid for pull and still reject push, so check the flag that matches the direction you need. Both flags are resolved from the card processor’s capability lookup at registration time, and either one is false when that capability is not reported — so read them rather than assuming a card that registered successfully can do both.
Store external_id — every payment call references it as external_payment_card_id.
Part 2 — Move money
Both payment endpoints take the same shape: which consumer, which registered card, how much, and an optional description. Both require api:write or api:purchase:write, and both read endpoints require api:read or api:purchase:read.
Push funds to the card (OCT)
Response — 200 OK:
Pull funds from the card (AFT)
Response — 200 OK:
A 200 means the payment was accepted and submitted to the card network — not
that it settled. Settlement is reported asynchronously by webhook.
Amounts and fees
amount is always the gross figure, and the fee comes out of it:
- OCT —
amountis debited from the consumer’s DDA. The card receivesamount - fee_amount. - AFT —
amountis debited from the card. The DDA is creditedamount - fee_amount.
Fees are configured per partner as a flat fee plus a percentage, capped at a maximum. The fee_amount on the response tells you exactly what was applied. If you need the consumer to receive an exact net figure, gross it up before you call.
For OCT, the consumer’s available DDA balance must cover the full amount.
Payment statuses
posted — not completed — is the settled state. Do not release goods or
credit a ledger on pending.
Webhooks
Subscribe to these events rather than polling. Every event carries a resources array with the URL of the payment to fetch.
See the full Event Catalog and Webhook Security.
Errors
Failures use the standard Upward error envelope:
Retrieving payments
Fetch a single payment by the id returned at creation:
Or list them for your partner, with page and page_size (max 50):
Both return 404 for payments belonging to another partner’s consumers.
Endpoint summary
Scopes are alternates — a token needs any one of the scopes listed for that endpoint, not all of them. Partner API Tokens generally carry the broad api:read / api:write; Customer Access Tokens carry the granular ones.
End-to-end example
Testing in sandbox
Sandbox is fully isolated and performs no live financial activity. Use it to exercise the whole path: mint a Customer Access Token, load the component, register a test card, then run an OCT and an AFT against it and confirm your webhook handler moves the payment through pending to posted.
See Sandbox Testing for test data and simulation endpoints.

