Maya Saved Cards

How Batchmates vaults card details with Maya and charges them later — without redirecting the user to a hosted page.

Maya's vaulting flow is browser-first: card data is tokenized directly in the browser against Maya's API. Batchmates servers never see raw card numbers.


Card Vaulting Flow

Step 1 — Tokenize in the browser

The frontend POSTs card details directly to Maya's tokenization endpoint using the public key (Basic Auth):

POST https://pg-sandbox.paymaya.com/payments/v1/payment-tokens
Authorization: Basic base64(MAYA_PUBLIC_KEY:)

Request

{
  "card": {
    "number": "4123450131001381",
    "expMonth": "12",
    "expYear": "2028",
    "cvc": "123",
    "name": "Juan Dela Cruz"
  }
}

Maya returns a paymentTokenId — a short-lived token representing the card. No raw card data ever reaches Batchmates.

Step 2 — Vault via backend

Endpoint: POST /api/v1/payment-methods/maya/link-card

Authentication: Required

Rate limit: 5 requests per minute

Send the paymentTokenId plus card metadata to the backend. The backend creates a Maya customer for the user (or reuses an existing one) and calls Maya's vault API.

  • Name
    payment_token_id
    Type
    string
    Description

    The paymentTokenId returned from Maya's tokenization endpoint

  • Name
    card_meta
    Type
    object
    Description

    Card metadata from the tokenization step

  • Name
    card_meta.last4
    Type
    string
    Description

    Last 4 digits of the card

  • Name
    card_meta.brand
    Type
    string
    Description

    Card brand (e.g. "visa", "mastercard")

  • Name
    card_meta.exp_month
    Type
    integer
    Description

    Expiration month (1–12)

  • Name
    card_meta.exp_year
    Type
    integer
    Description

    Expiration year (4 digits)

Request

{
  "payment_token_id": "8iDnJOw10fA6J6HR...",
  "card_meta": {
    "last4": "1381",
    "brand": "visa",
    "exp_month": 12,
    "exp_year": 2028
  }
}

Response

{
  "success": true,
  "data": {
    "id": 12,
    "payment_gateway": "maya",
    "card_last_four": "1381",
    "card_brand": "visa",
    "is_default": true,
    "is_vaulted": true
  },
  "message": "Card linked successfully"
}

Internal Vaulting Sequence

// app/Services/MayaTransactionService.php

public function linkCard(int $userId, string $paymentTokenId, array $cardMeta): PaymentMethod
{
    // Reuse existing Maya customer or create new one
    $customerId = $existingCustomerId ?? $this->maya->createCustomer([...])['id'];

    // Vault the token → returns cardTokenId (long string)
    $card = $this->maya->linkCard($customerId, $paymentTokenId, $refNumber);
    $cardTokenId = $card['cardTokenId'];

    return PaymentMethod::create([
        'payment_gateway'     => 'maya',
        'gateway_token'       => $cardTokenId,       // long card token
        'gateway_customer_id' => $customerId,        // Maya customer UUID
        ...
    ]);
}

POST/api/v1/donations/charge-saved/maya

Charging a Saved Maya Card

Charges a saved Maya card directly, bypassing hosted checkout.

Authentication: Required

Rate limit: 5 requests per minute

Request Body

  • Name
    campaign_id
    Type
    integer
    Description

    ID of the campaign to donate to

  • Name
    payment_method_id
    Type
    integer
    Description

    ID of the saved Maya payment method. Must belong to the authenticated user and have payment_gateway = "maya".

  • Name
    amount
    Type
    number
    Description

    Donation amount in PHP (minimum: 1)

  • Name
    is_anonymous
    Type
    boolean
    Description

    Make donation anonymous. Default: false

  • Name
    message
    Type
    string
    Description

    Optional message to the campaign (max 500 characters)

Request

{
  "campaign_id": 1,
  "payment_method_id": 12,
  "amount": 500
}

Response (completed)

{
  "success": true,
  "data": {
    "id": 88,
    "amount": "500.00",
    "status": "completed",
    "payment_gateway": "maya",
    "paid_at": "2025-03-01T08:00:00.000000Z"
  },
  "message": "Donation charged successfully"
}

Response (3DS required)

{
  "success": false,
  "requires_action": true,
  "action_url": "https://payments-web-sandbox.maya.ph/authenticate?id=...",
  "message": "Payment requires authentication"
}

3DS Authentication

When requires_action: true is returned:

  1. Redirect the user to action_url
  2. Maya presents the 3DS challenge
  3. After authentication, Maya redirects back to /api/v1/payments/maya/success
  4. The backend verifies the payment with Maya's API and marks the donation completed

Vaulted Card Status

All PaymentMethod records expose an is_vaulted computed field — true when both gateway_customer_id and gateway_token are present. The raw token values are never returned in API responses.


What Cannot Be Vaulted

Only credit/debit cards support vaulting.


Mobile / Native Clients

The vaulting and charge endpoints are platform-neutral, but the card-capture step shown here is written for the web. On native clients:

Was this page helpful?