Skip to main content
Saving a card starts by creating a payment method via the Compago API. This returns a checkout URL where your customer securely enters their card details. Once the card is verified, it’s stored securely and you can charge it on demand.

Creating a Payment Method

Endpoint

POST /api/payment-method
API reference: POST /payment-method

Authentication

Include your API key in the request headers:
x-api-key: YOUR_API_KEY
Content-Type: application/json

Request Body

{
  "externalId": "customer_12345",
  "verificationAmount": 1,
  "billingInformation": {
    "email": "maria.gonzalez@example.com",
    "firstName": "María",
    "lastName": "González",
    "phoneNumber": "+5215512345678"
  },
  "displayMode": "LINK",
  "redirectUrl": "https://yourstore.com/cards/saved",
  "ttlMinutes": 2880
}

Field Descriptions

FieldTypeRequiredDescription
externalIdstringNoYour unique identifier for this payment method (e.g., customer ID).
verificationAmountnumberNoAmount in MXN for the verification charge. Minimum 1 MXN. Defaults to 1 MXN.
billingInformationobjectYesCustomer billing details (see below).
displayModestringNo"LINK" (default) for full-page redirect or "EMBEDDED" for iframe. See Display Modes.
buttonTextstringNoCustom text for the checkout button (EMBEDDED mode only).
buttonColorstringNoCustom hex color for the checkout button, e.g. "#16A34A" (EMBEDDED mode only).
redirectUrlstringNoURL where the customer is redirected after saving their card. Compago appends id and externalId as query parameters.
ttlMinutesintegerNoTime-to-live in minutes for the checkout link. Minimum 1 minute. Defaults to 2,880 (48 hours).

Billing Information

FieldTypeRequiredDescription
emailstringYesCustomer’s email address.
firstNamestringYesCustomer’s first name.
lastNamestringYesCustomer’s last name.
phoneNumberstringYesCustomer’s phone number (include country code, e.g., +521…).

Response

{
  "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "checkoutUrl": "https://app.compago.com/checkout/pm/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
}
FieldTypeDescription
idstringUnique identifier of the payment method. Use this to charge, retrieve, or revoke it later.
checkoutUrlstringURL where the customer completes the card-saving process.

Code Examples

curl -X POST https://api.harmony.compago.com/api/payment-method \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "customer_12345",
    "verificationAmount": 1,
    "billingInformation": {
      "email": "maria.gonzalez@example.com",
      "firstName": "María",
      "lastName": "González",
      "phoneNumber": "+5215512345678"
    },
    "redirectUrl": "https://yourstore.com/cards/saved",
    "ttlMinutes": 2880
  }'

Display Modes

Compago supports two display modes for the card-saving checkout experience. In LINK mode, you redirect the customer to the checkoutUrl returned by the API. The customer completes the card-saving flow on a full-page Compago checkout page and is then redirected back to your redirectUrl. This is the simplest integration. Just redirect the customer:
// After creating the payment method
window.location.href = checkoutUrl;

EMBEDDED Mode

In EMBEDDED mode, you embed the checkoutUrl in an iframe on your own page. This keeps the customer on your site throughout the process. You can customize the checkout button appearance using buttonText and buttonColor.
{
  "displayMode": "EMBEDDED",
  "buttonText": "Save My Card",
  "buttonColor": "#16A34A",
  "billingInformation": { ... },
  "redirectUrl": "https://yourstore.com/cards/saved"
}
Embed the checkout URL in your page:
<div style="width: 100%; max-width: 500px; margin: 0 auto;">
  <iframe
    src="https://app.compago.com/checkout/pm/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    width="100%"
    height="600"
    frameborder="0"
    allow="payment"
    style="border: none; border-radius: 8px;"
  ></iframe>
</div>
In EMBEDDED mode, the iframe handles the entire card-saving flow. You can listen for iframe events to react to success and error states in real time, or use a redirectUrl to handle the result via a page redirect. For more details, see Handling the Result.

Verification Charge

When a customer saves their card, Compago places a small verification charge to validate that the card is real and has sufficient funds. This charge is automatically voided (reversed). The customer is not actually billed.
  • Default amount: 1 MXN
  • Minimum amount: 1 MXN
  • What happens: The charge appears temporarily on the customer’s statement and is then voided
You can customize the verification amount:
{
  "verificationAmount": 5,
  "billingInformation": { ... }
}
Set the verification amount close to the actual amount you plan to charge the customer later. Issuer banks are more likely to automatically reject future charges that differ significantly from the verification amount, so a closer match reduces the risk of payment declines.
Some banks may show the verification charge as a pending transaction for a few days before it disappears. Consider notifying your customers about this.

Handling the Result

After a customer completes the card-saving checkout, you need to handle the result. There are two approaches depending on your integration.

Using the Redirect URL

When a customer successfully saves their card, Compago redirects them back to your redirectUrl with two query parameters:
  • id: The Compago payment method ID
  • externalId: The external ID you provided when creating the payment method
For example, if you created a payment method with:
{
  "redirectUrl": "https://yourstore.com/cards/saved",
  "externalId": "customer_12345"
}
The customer will be redirected to:
https://yourstore.com/cards/saved?id=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee&externalId=customer_12345

Redirect Implementation

app.get('/cards/saved', async (req, res) => {
  const { id, externalId } = req.query;

  if (!id || !externalId) {
    return res.status(400).send('Missing parameters');
  }

  // Fetch the payment method to confirm it's ACTIVE
  const response = await fetch(
    `https://api.harmony.compago.com/api/payment-method/${id}`,
    {
      headers: { 'x-api-key': process.env.COMPAGO_API_KEY }
    }
  );

  const paymentMethod = await response.json();

  if (paymentMethod.status === 'ACTIVE') {
    // Card saved successfully - store the payment method ID
    await savePaymentMethodForCustomer(externalId, id);
    res.render('card-saved-success', {
      lastFour: paymentMethod.card?.lastFourDigits,
      network: paymentMethod.card?.networkType
    });
  } else {
    res.render('card-save-pending', { status: paymentMethod.status });
  }
});

Using Iframe Events (EMBEDDED Mode)

In EMBEDDED mode, the checkout iframe sends postMessage events to the parent window so you can react to loading, success, and error states without waiting for a redirect.

Events Reference

Event TypePayloadWhen Fired
COMPAGO_PAYMENT_METHOD_LOADING{ type }Checkout iframe loads
COMPAGO_PAYMENT_METHOD_SUCCESS{ type, data: { paymentMethodId, cardLastFour, cardNetwork, billingEmail } }Card saved successfully
COMPAGO_PAYMENT_METHOD_ERROR{ type, error: { code, message } }Card verification fails

Listening for Events

window.addEventListener('message', (event) => {
  // Filter to only Compago payment method events
  if (!event.data?.type?.startsWith('COMPAGO_PAYMENT_METHOD_')) {
    return;
  }

  switch (event.data.type) {
    case 'COMPAGO_PAYMENT_METHOD_LOADING':
      console.log('Checkout is loading...');
      // Show a loading indicator in your UI
      break;

    case 'COMPAGO_PAYMENT_METHOD_SUCCESS':
      console.log('Card saved!', event.data.data);
      // { paymentMethodId, cardLastFour, cardNetwork, billingEmail }
      const { paymentMethodId, cardLastFour } = event.data.data;
      // Verify via API, then store the payment method
      verifyAndStoreCard(paymentMethodId, cardLastFour);
      break;

    case 'COMPAGO_PAYMENT_METHOD_ERROR':
      console.error('Checkout error:', event.data.error);
      // { code, message }
      showErrorMessage(event.data.error.message);
      break;
  }
});

Event Payloads

Loading event:
{
  "type": "COMPAGO_PAYMENT_METHOD_LOADING"
}
Success event:
{
  "type": "COMPAGO_PAYMENT_METHOD_SUCCESS",
  "data": {
    "paymentMethodId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
    "cardLastFour": "4242",
    "cardNetwork": "VISA",
    "billingEmail": "maria.gonzalez@example.com"
  }
}
Error event:
{
  "type": "COMPAGO_PAYMENT_METHOD_ERROR",
  "error": {
    "code": "CARD_DECLINED",
    "message": "The card was declined by the issuing bank."
  }
}
Validate that event.data.type starts with COMPAGO_PAYMENT_METHOD_ before processing. This filters out unrelated postMessage events from other scripts or browser extensions.
Even when using iframe events, always verify the payment method status via the API before trusting the result. The COMPAGO_PAYMENT_METHOD_SUCCESS event confirms the checkout completed, but your backend should call GET /api/payment-method/{id} to confirm the status is ACTIVE before storing the card for future charges.

Best Practices

After the customer is redirected back, always fetch the payment method from the API to confirm its status is ACTIVE before storing it for future charges.
const paymentMethod = await fetchPaymentMethod(id);
if (paymentMethod.status !== 'ACTIVE') {
  // Handle non-active status
}
Save the Compago payment method id in your database associated with the customer. You’ll need this ID to charge the card later.
await db.customers.update(externalId, {
  compagoPaymentMethodId: id,
  cardLastFour: paymentMethod.card?.lastFourDigits,
  cardNetwork: paymentMethod.card?.networkType
});
Let customers know that a small temporary charge will appear on their statement during the card verification process. This prevents confusion and support requests.
If the checkout link expires before the customer saves their card, create a new payment method and send the customer the updated checkout URL.
Always use HTTPS URLs for your redirectUrl to ensure query parameters are transmitted securely.

Error Handling

Status CodeErrorSolution
400Invalid billing informationEnsure all required billing fields are provided and valid.
400Missing organization contextVerify your organization settings are configured correctly.
401UnauthorizedCheck your API key is valid and included in headers.

Security Considerations

Never skip verification! The redirect URL is visible to the customer and could be manipulated. Always fetch the payment method status from Compago’s API using the id parameter before storing it.
Your redirect implementation should:
  1. Validate query parameters exist before processing
  2. Fetch payment method status from Compago API. Don’t trust the redirect alone
  3. Verify the externalId matches your records. Ensure it corresponds to a real customer in your system
  4. Check status is ACTIVE before allowing future charges
  5. Log all redirect attempts for debugging and security monitoring

Next Steps

Charge a Saved Card

Learn how to charge a customer’s saved card on demand.

Manage Payment Methods

List, retrieve, and revoke saved payment methods.