Link a Debit Card

⚠️

The Debit Card feature is currently available only for Individual customers. Business customers are not yet supported.

📧

Before executing an Debit Card Pull transaction, OwlPay will send an authorization email to the Customer requesting their approval. The email will clearly identify which Application is initiating the pull request.

Prerequisites

  1. Your Application has the DEBIT_CARD payment method enabled
  2. The Customer has completed KYC verification (status: VERIFIED)
  3. The Customer has completed bank compliance onboarding (CRB Bank Onboarding status: ONBOARDED)
📋

Support Coverage Notice: Before integrating, please review the eligible card types, network brands, and countries in the Debit Card Support Coverage guide. Note that credit cards are not supported.

Flow Overview

1. Bind Card       → User completes card binding via the binding page
2. List Cards      → Retrieve the list of linked cards
3. Get Quote       → Get a DEBIT_CARD quote
4. Create Transfer → Submit a transfer with the card ID
5. Email Notification → OwlPay sends a notification email to the cardholder

Important: When a Debit Card transfer is created, OwlPay will send a notification email to the cardholder informing them of the upcoming charge. Please ensure the user is aware of this process.


Step 1: Bind Card

Generate a card binding URL for the customer and redirect them to complete card authorization and binding.

Request

curl --location --request POST 'https://harbor-sandbox.owlpay.com/api/v1/customers/{{CUSTOMER_UUID}}/cards' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--data-raw '{
    "redirect_url": {
        "success": "https://yourapp.com/card/success",
        "failed": "https://yourapp.com/card/failed"
    }
}'
ParameterTypeRequiredDescription
redirect_url.successstringNoRedirect URL after successful binding. Supports web links or app deep links
redirect_url.failedstringNoRedirect URL on binding failure. Supports web links or app deep links

Response (201)

{
    "data": {
        "uuid": "card_abc123",
        "object": "customer_card",
        "customer_uuid": "cus_1234567890",
        "status": "pending",
        "last4_digits": null,
        "card_company": null,
        "pull_enabled": false,
        "push_enabled": false,
        "first_name": null,
        "last_name": null,
        "country_code": null,
        "issuer_country_code": null,
        "enabled": false,
        "restricted": false,
        "url": "https://card-binding.example.com/bind/card_abc123",
        "created_at": "2026-03-21T10:00:00+00:00",
        "updated_at": "2026-03-21T10:00:00+00:00"
    }
}
📘

Card Information for Testing

For testing purposes, you may use the card number 4242424242424242. Ensure the expiration date is set to 12/31, the CVV to 123, and use 12345 as the postal/zip code to bypass validation during the integration process.

More Cards for Testing:

Mastercard (Debit)VISA OCT (Prepaid)VISA OCT (Debit)
510258999999990540002899999999084007589999999904
510258999999991340002899999999164007589999999912
510258999999992140002899999999244007589999999920
510258999999993940002899999999324007589999999938
510258999999994740002899999999404007589999999946
510258999999995440002899999999574007589999999953
510258999999996240002899999999654007589999999961
510258999999997040002899999999734007589999999979
510258999999998840002899999999814007589999999987
510258999999999640002899999999994007589999999995

Integration

Present the returned url to the user via redirect or iframe. After the user completes card information entry on the binding page, the card status will change from pending to active, with enabled set to true, making it ready for transactions.

Note: When status is pending, the returned url is the card binding page link. Once the card is activated, url becomes null.


Step 2: List Cards

After the user completes card binding, call this API to retrieve the list of linked cards. The system automatically syncs the latest card status from upstream.

Request

curl --location --request GET 'https://harbor-sandbox.owlpay.com/api/v1/customers/{{CUSTOMER_UUID}}/cards' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}'

Response (200)

{
    "data": [
        {
            "uuid": "card_abc123",
            "object": "customer_card",
            "customer_uuid": "cus_1234567890",
            "status": "active",
            "last4_digits": "4242",
            "card_company": "Visa",
            "pull_enabled": true,
            "push_enabled": false,
            "first_name": "JOHN",
            "last_name": "DOE",
            "country_code": "US",
            "issuer_country_code": "US",
            "enabled": true,
            "restricted": false,
            "url": null,
            "created_at": "2026-03-21T10:00:00+00:00",
            "updated_at": "2026-03-21T10:05:00+00:00"
        }
    ]
}
FieldDescription
uuidUnique card identifier, prefixed with card_. This ID is required in Step 4 when creating a transfer
statusCard status: pending, active, expired, disabled, restricted
last4_digitsLast 4 digits of the card number
card_companyCard network (e.g., Visa, Mastercard)
pull_enabledWhether the card supports pull (debit) transactions
enabledWhether the card is enabled for transactions. Only cards with true can be used
restrictedWhether the card is restricted. If true, the card cannot be used

Only cards with status: active, enabled: true, and restricted: false can be used to initiate transactions.


Step 3: Get Debit Card Quote

Before initiating a transfer, get a quote to confirm the exchange rate, fees, and settlement amount.

Request

curl --location --request POST 'https://harbor-sandbox.owlpay.com/api/v2/transfers/quotes' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--data-raw '{
    "on_behalf_of": "{{CUSTOMER_UUID}}",
    "source_amount": "100.00",
    "source_currency": "USD",
    "destination_currency": "USDC"
}'

Response (200)

The response includes quotes for multiple payment methods. Select the item where payment_method is DEBIT_CARD.

[
    {
        "id": "quote_f03AirZ3ZY...KBtFQfZtPDYv",
        "payment_method": "DEBIT_CARD",
        "source_amount": "100.00",
        "source_currency": "USD",
        "destination_amount": "99.50",
        "destination_currency": "USDC",
        "fee": "0.50",
        "quote_expire_date": "2026-03-21T09:30:00Z",
        "customer_limits": {
            "per_transaction_limit": "500.00",
            "daily_limit": "5000.00",
            "weekly_limit": "20000.00",
            "monthly_limit": "100000.00",
            "daily_spent": "0.00",
            "daily_remaining": "5000.00",
            "weekly_spent": "0.00",
            "weekly_remaining": "20000.00",
            "monthly_spent": "0.00",
            "monthly_remaining": "100000.00",
            "current_remaining": "500.00"
        }
    }
]

Save the id (i.e., quote_id) from the DEBIT_CARD quote — it is required in the next step to create the transfer. When on_behalf_of is provided, the response includes customer_limits which can be used to display the user's transaction limits on the frontend.


Step 4: Create Debit Card Transfer

Use the card_ ID from Step 2 and the quote_id from Step 3 to create the transfer.

Settlement Time Notice: Debit Card transfers typically settle in T+1 business days. For more details on fund availability and payment locks, see Settlement and Payment Lock Time.

Request

curl --location --request POST 'https://harbor-sandbox.owlpay.com/api/v2/transfers' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--header 'Idempotency-Key: {{Idempotency-Key}}' \
--data-raw '{
    "on_behalf_of": "{{CUSTOMER_UUID}}",
    "quote_id": "{{QUOTE_ID}}",
    "application_transfer_uuid": "{{YOUR_ORDER_ID}}",
    "source": {
        "payment_instrument": {
            "linked_card_id": "card_abc123"
        }
    },
    "destination": {
        "beneficiary_info": {
            "...": "Fill according to quote requirements"
        },
        "payout_instrument": {
            "address": "0x1234567890abcdef1234567890abcdef12345678"
        },
        "transfer_purpose": "SALARY",
        "is_self_transfer": true
    }
}'
ParameterTypeRequiredDescription
on_behalf_ofstringYesCustomer UUID
quote_idstringYesQuote ID obtained in Step 3
application_transfer_uuidstringYesYour order ID (used for idempotency)
source.payment_instrument.linked_card_idstringYesCard ID from Step 2 (prefixed with card_)
destinationobjectYesDestination information (payout address, beneficiary details, etc.)

Response (201 Created)

On success, returns the full Transfer object with an initial status of PENDING_CUSTOMER_TRANSFER_START.

Error Scenarios

HTTP StatusReason
422Card does not exist or does not belong to this Application
422Card status is not active
422Card is not enabled (enabled is false)
422Card is restricted (restricted is true)
422Card has been blocklisted
422Transaction limit exceeded (per-transaction / daily / weekly / monthly)
404Customer not found or does not belong to this Application

Email Notification

When a Debit Card transfer is successfully created, OwlPay will automatically send a notification email to the cardholder containing:

  • Charge amount and currency
  • Transaction details

This email ensures the cardholder is aware of the upcoming charge, in compliance with regulatory requirements. No additional action is needed from the Application side for this notification.


Complete Flow Diagram


Transfer Status Flow

StatusDescription
PENDING_CUSTOMER_TRANSFER_STARTTransfer created, awaiting processing
PENDING_HARBORBeing processed
COMPLETEDTransfer complete, funds settled
REJECTTransfer rejected
ON_HOLDTransfer temporarily frozen (may require additional review)

We recommend listening for transfer status changes via Webhooks to keep your system updated in real time.