Guides / Payments
Saved cards
Save your customer’s card once, then charge it whenever you need to, with no customer present: subscriptions, top-ups, auto-debit. Your customer types their card on a Weav page, so card numbers never reach your systems.
Saving cards is off until Weav turns it on for your account. Weav asks for your PCI DSS evidence first. In test mode it always works, so you can build your integration now.
1. Save the card
Save it while your customer pays, or on its own.
While they pay
Add save_payment_method and customer.id to a CARD payment:
POST /v1/payments
{ "channel": "CARD", "currency": "PHP", "amount": 499.00, "external_reference_id": "SUB-USER-123-2026-10", "save_payment_method": true, "customer": { "id": "USER-123", "name": "Juan dela Cruz" }, "success_url": "https://shop.example/account/plan" }Send your customer to next_action.checkout_url, Weav’s payment page, as for any payment. There they type their card, agree that you may charge it for future payments, and confirm the payment with their bank. That one check also confirms the card: there’s no ₱10.00 check.
sequenceDiagram
autonumber
actor Customer as Your customer
participant Server as Your server
participant Weav
participant Bank as Their bank
Server->>Weav: POST /v1/payments<br/>CARD, save_payment_method, customer.id
Weav-->>Server: 201 PENDING, payment_method_id<br/>next_action.checkout_url
Server-->>Customer: Sends them to checkout_url
Customer->>Weav: Types their card, agrees to future charges
Note over Customer,Weav: The card number never reaches your server
Weav->>Bank: Charges the card
Bank-->>Customer: Asks them to confirm it's them
Customer->>Bank: Confirms
alt Paid
Weav-->>Customer: Redirects to success_url
Weav->>Server: PAYMENT_COMPLETED webhook
Weav->>Server: PAYMENT_METHOD_SAVED webhook<br/>the card is ACTIVE
Note over Server: Keep the card's id (PM…)<br/>with your customer
else Not paid
Weav->>Server: PAYMENT_FAILED, then<br/>PAYMENT_METHOD_FAILED webhooks
Note over Weav: The card isn't kept
endThe response’s payment_method_id is the new saved card, PENDING until the payment is paid. Then you get two webhooks:
PAYMENT_COMPLETED, thenPAYMENT_METHOD_SAVED: the card isACTIVE. Charge it next time with itsid(step 2).- If the payment isn’t paid, the card isn’t kept:
PAYMENT_FAILED, thenPAYMENT_METHOD_FAILED.
A checkout takes the same save_payment_method and customer.id. If your customer pays by card, the card is saved the same way. Another way to pay saves nothing, so send "channels": ["CARD"] to take cards only.
On its own
POST /v1/payment-methods
{ "type": "CARD", "customer": { "id": "USER-123", "name": "Juan dela Cruz", "email": "juan@example.com" }, "success_url": "https://shop.example/account/cards" }customer.id is your own ID for your customer. You get a payment method with status: PENDING and next_action.checkout_url. Send your customer there. On Weav’s save page they:
- Give their name, if you didn’t send it.
- Type their card and agree that you may charge it for future payments.
- Confirm it with their bank. Their bank may show a ₱10.00 check that is canceled right after.
sequenceDiagram
autonumber
actor Customer as Your customer
participant Server as Your server
participant Weav
participant Bank as Their bank
Server->>Weav: POST /v1/payment-methods<br/>CARD, customer.id
Weav-->>Server: 201 PENDING<br/>next_action.checkout_url
Server-->>Customer: Sends them to checkout_url
Customer->>Weav: Their name if you didn't send it,<br/>their card, and their agreement
Weav->>Bank: Checks the card
Bank-->>Customer: Asks them to confirm<br/>(may show a ₱10.00 check)
Customer->>Bank: Confirms
alt The bank confirms it
Weav-->>Customer: Redirects to success_url
Weav->>Server: PAYMENT_METHOD_SAVED webhook<br/>the card is ACTIVE
else The check fails, or the link isn't used in 24 hours
Weav->>Server: PAYMENT_METHOD_FAILED webhook
endThen they go back to your success_url (or cancel_url), and you get a webhook:
PAYMENT_METHOD_SAVED: it’sACTIVE. Keep itsid(PM…) with your customer. Showlabel(“Visa •••• 1381”) so they know which card it is.PAYMENT_METHOD_FAILED: the bank’s check failed, or the link wasn’t used within 24 hours.
2. Charge it
POST /v1/payments
{ "payment_method_id": "PM8K2Q7X9KBAT4MZ3N", "currency": "PHP", "amount": 499.00, "external_reference_id": "SUB-USER-123-2026-11" }No channel, no customer, no URLs. A saved card is usually paid at once: the response says COMPLETED, and you get PAYMENT_COMPLETED. If the card can’t be charged, it’s FAILED. Sometimes the bank asks your customer to confirm again: the payment stays PENDING with next_action.type REDIRECT, so send your customer to checkout_url.
sequenceDiagram
autonumber
participant Server as Your server
participant Weav
actor Customer as Your customer
Server->>Weav: POST /v1/payments<br/>payment_method_id, amount, external_reference_id
alt Paid, as most charges are
Weav-->>Server: 201 COMPLETED
Weav->>Server: PAYMENT_COMPLETED webhook
else The bank wants your customer to confirm
Weav-->>Server: 201 PENDING<br/>next_action.checkout_url
Server-->>Customer: Sends them the link
Customer->>Weav: Confirms with their bank
Weav->>Server: PAYMENT_COMPLETED webhook
else The card can't be charged
Weav-->>Server: 201 FAILED
Weav->>Server: PAYMENT_FAILED webhook
endRetries are safe: send the same request with the same external_reference_id (see Idempotency).
3. List and remove
GET /v1/payment-methods?customer_id=USER-123: your customer’s saved cards.GET /v1/payment-methods?expires_by=2026-12: cards that expire by then. Each card hasexp_monthandexp_year, so you can ask for a new card in time.GET /v1/payments?payment_method_id=PM8K2Q7X9KBAT4MZ3N: every charge on a saved card.DELETE /v1/payment-methods/{id}: removes it, at the card processor too, so nobody can charge it again (PAYMENT_METHOD_REMOVED). Remove a card whenever your customer asks.
Good to know
- Your customer’s agreement. The save page records that your customer let you charge the card. Charge only what you told them you would (amounts and timing).
- In a mobile app, open the save page in the system browser or an in-app browser tab (
SFSafariViewControlleron iOS, Custom Tabs on Android), not a WebView your app controls. - Test mode has a test save page with three test cards: one that’s paid, one that’s declined, and one that expires this month. See Test mode.
- Subscriptions: charge a saved card on your own schedule. See Subscriptions.
- Only cards for now (Visa, Mastercard, JCB).