RapidCents Developer Documentation
Payment Link Integration Guide
v1.0 · REST API

Payment Links

Create shareable payment links · Email & SMS delivery · Card & Google Pay acceptance

Summary

Payment Links allow merchants to request payment from customers without building a custom checkout. The merchant creates a link via the API, shares it by email or SMS, and the customer pays through a hosted payment page.

🔗

Payment Links support manual card entry, saved cards, and Google Pay. Optional 3D Secure can be enabled per link.

Payment Link Lifecycle

  1. Create — Merchant creates a payment link via the API with customer, amount, and optional description.
  2. Share — RapidCents automatically sends the link to the customer via email. The merchant can also resend by email or SMS.
  3. View — Customer opens the link and sees the hosted payment page with amount, merchant details, and payment form.
  4. Pay — Customer enters card details (or uses Google Pay) and submits payment. 3D Secure step-up is triggered if enabled.
  5. Result — On approval, the link status changes to PAID. Both merchant and customer receive a payment confirmation notification.

Payment Link Statuses

CREATED

New link, unpaid. Can be edited, resent, or deleted.

EXPIRED

No longer payable. Expired due to max attempts, 3DS failure, or due date.

Expiry Reasons

CodeReasonDescription
1Max AttemptsCustomer exceeded the maximum number of failed payment attempts
23D Secure Failure3D Secure authentication failed
3Phone Verification FailurePhone verification step failed
4Due Date ExpiredLinked invoice due date has passed

Processing Flow

MerchantCreates Link via API
RapidCentsSends Email / SMS
CustomerOpens & Pays
RapidCentsValidates & Processes
3D SecureInit · Authenticate · Challenge
Visa · Mastercard · Discover · Amex

Authentication

ScopeAuth RequiredDetails
Merchant API (create, list, update, delete, resend)YesBearer <access_token> + business ID in URL
Customer (Public) (view, pay)NoPayment link ID in URL acts as access token

Create Payment Link

POST /api/{business_id}/payment_links

Request Body
{
  "customerId": "customer-uuid",
  "amount": 50.00,
  "description": "Invoice #1001 - Web Design Services",
  "customInvoiceNumber": "INV-1001",
  "merchant_description": "Internal note for this link",
  "surcharge": 2.50,
  "threeDSecure": true
}

Create Fields

FieldTypeRequiredDescription
customerIdstringYesCustomer UUID
amountnumberYesPayment amount
descriptionstringNoDescription shown to customer
customInvoiceNumberstringNoCustom invoice reference
merchant_descriptionstringNoInternal note (not shown to customer)
surchargenumberNoAdditional surcharge amount
threeDSecurebooleanNoEnable 3D Secure for this link
Response
{
  "ok": true,
  "payment_link": {
    "id": "pl-uuid",
    "amount": 50.00,
    "status": "CREATED",
    "url": "https://pay.rapidcents.com/payment-links/pl-uuid",
    "created_at": "2026-02-26T12:00:00Z"
  }
}

List Payment Links

GET /api/{business_id}/payment_links

Response
{
  "ok": true,
  "payment_links": {
    "data": [ /* array of payment link objects */ ],
    "current_page": 1,
    "last_page": 5,
    "per_page": 10,
    "total": 48
  },
  "filters": {
    "fromDate": "2026-01-01",
    "toDate": "2026-02-26"
  }
}

Get Link Details

GET /api/{business_id}/payment_links/{payment_link_id}

Update Payment Link

PUT /api/{business_id}/payment_links/{payment_link_id}

⚠️

A payment link can only be updated when its status is CREATED and any attached contract is unsigned.

Request Body
{
  "amount": 75.00,
  "description": "Updated description"
}

Delete Payment Link

DELETE /api/{business_id}/payment_links/{payment_link_id}

🗑

A payment link can only be deleted when its status is not PAID and any attached contract is unsigned.

Resend Payment Link

POST /api/{business_id}/payment_links/{payment_link_id}/resend

Resends the payment link notification to the customer via email. If the link has already been paid, a receipt is sent instead.

Payment Attempts

GET /api/{business_id}/payment_links/{payment_link_id}/attempts

Returns a list of all payment attempts made on this link, including failed attempts with decline reasons.

Pay with Card (Public)

POST /api/payment_links/{payment_link_id}/pay

Request Body
{
  "cardData": {
    "cardNumber": "4111111111111111",
    "month": "12",
    "year": "2028",
    "cvv": "123",
    "nameOnCard": "John Doe",
    "saveCard": false,
    "address": {
      "line1": "123 Main St",
      "postalCode": "M5V 2T6"
    }
  }
}

Card Payment Fields

FieldTypeRequiredDescription
cardData.cardNumberstringYesFull card number
cardData.monthstringYesExpiration month (2 digits)
cardData.yearstringYesExpiration year
cardData.cvvstringYesCVV
cardData.nameOnCardstringYesCardholder name
cardData.saveCardbooleanNoSave card for future payments
cardData.address.line1stringYesBilling address
cardData.address.postalCodestringYesBilling postal code

With 3D Secure

If the payment link has threeDSecure enabled, include the 3DS session data:

{
  "cardData": { /* ... card fields ... */ },
  "ddd": { /* 3D Secure authentication data */ },
  "dddSessionID": "3ds-session-uuid"
}
Response — Approved
{
  "ok": true,
  "result": {
    "status": "Approved",
    "auth_code": "123456",
    "amount": 50.00
  }
}

3D Secure (3DS) Flow

When a payment link has threeDSecure enabled, the customer must complete 3D Secure authentication before the payment is processed. This adds an extra layer of cardholder verification.

🛡

3D Secure is applied only when both the business has 3DS enabled and the individual payment link has threeDSecure: true.

3DS Step-by-Step Flow

  1. View Payment LinkGET /api/payment_links/{id}/pay returns three_d_secure: true indicating 3DS is required.
  2. Init (Card Lookup) — Client calls POST /api/{business_id}/ddd/init with card details to check 3DS support and create a session.
  3. Authenticate — If init returns DDD_INVOKE, client calls POST /api/{business_id}/ddd/authenticate to start authentication.
  4. Challenge (if required) — If authenticate returns status C, the customer is redirected to the bank's ACS page to complete the challenge.
  5. Pay — Client submits the payment with ddd (3DS result) and dddSessionID to POST /api/payment_links/{id}/pay.

Step 1: Init (Card Lookup)

POST /api/{business_id}/ddd/init

Request Body
{
  "cardData": {
    "cardNumber": "4111111111111111",
    "month": "12",
    "year": "2028"
  },
  "paymentLinkID": "payment-link-uuid"
}

Init Response — Frictionless (no challenge needed)

JSON
{
  "ok": true,
  "status": "DDD_FRICTIONLESS",
  "data": {
    "threeDSServerTransID": "trans-id",
    "association": "visa",
    "sessionID": "session-id"
  }
}

Init Response — Challenge Required

JSON
{
  "ok": true,
  "status": "DDD_INVOKE",
  "data": {
    "threeDSMethodURL": "https://acs.bank.com/3ds-method",
    "threeDSMethodData": "base64-data",
    "threeDSServerTransID": "trans-id",
    "association": "visa",
    "sessionID": "session-id"
  }
}

Init Response — 3DS Not Supported

JSON
{
  "ok": false,
  "status": "DDD_NOT_SUPPORTED",
  "message": "Card does not support 3D Secure"
}

Step 2: Authenticate

POST /api/{business_id}/ddd/authenticate

Request Body
{
  "threeDSServerTransID": "from-init-response",
  "sessionID": "from-init-response",
  "email": "[email protected]",
  "cardData": {
    "nameOnCard": "John Doe",
    "cardNumber": "4111111111111111",
    "month": "12",
    "year": "2028",
    "cvv": "123"
  },
  "amount": 50.00
}

Authenticate Response — Success (Frictionless)

JSON
{
  "status": "Y",
  "message": "OK",
  "data": {
    "transStatus": "Y",
    "authenticationValue": "base64-cavv-value",
    "eci": "05"
  },
  "sessionID": "session-id"
}

Authenticate Response — Challenge Required

JSON
{
  "status": "C",
  "message": "OK",
  "data": {
    "creq": "base64-challenge-request",
    "acsURL": "https://acs.bank.com/challenge",
    "threeDSSessionData": "trans-id"
  },
  "sessionID": "session-id"
}

Step 3: Challenge (Bank Redirect)

🏦

When the authenticate response returns status C, redirect the customer to the acsURL with the creq data. The bank will present a challenge (OTP, biometric, etc.). After completion, the bank posts the result back to your callback URL.

Step 4: Pay with 3DS Data

After 3DS authentication completes (frictionless or challenge), include the 3DS result in the payment request:

Frictionless Payment

Request Body
{
  "cardData": {
    "cardNumber": "4111111111111111",
    "month": "12",
    "year": "2028",
    "cvv": "123",
    "nameOnCard": "John Doe",
    "address": {
      "line1": "123 Main St",
      "postalCode": "M5V 2T6"
    }
  },
  "ddd": {
    "transStatus": "Y",
    "authenticationValue": "base64-cavv-value",
    "eci": "05",
    "association": "visa"
  },
  "dddSessionID": "session-id"
}

Challenge Payment

Request Body
{
  "cardData": {
    "cardNumber": "4111111111111111",
    "month": "12",
    "year": "2028",
    "cvv": "123",
    "nameOnCard": "John Doe",
    "address": {
      "line1": "123 Main St",
      "postalCode": "M5V 2T6"
    }
  },
  "ddd": {
    "creq": "base64-challenge-request"
  },
  "dddSessionID": "session-id"
}

3DS Authentication Statuses

StatusMeaningAction
YAuthenticatedProceed with payment (include ddd data)
AAttemptedProceed with payment (liability shift may apply)
CChallenge requiredRedirect customer to acsURL for bank challenge
NNot authenticatedAuthentication failed — do not proceed
UUnavailable3DS server unavailable — merchant decides risk
RRejectedAuthentication rejected — do not proceed

3DS Endpoints Summary

MethodEndpointDescription
POST/api/{business_id}/ddd/initStart 3DS session & card lookup
POST/api/{business_id}/ddd/authenticateRun 3DS authentication

Pay with Google Pay (Public)

POST /api/payment_links/{payment_link_id}/pay

Request Body
{
  "googlePay": {
    "payment_token": "{\"signature\":\"...\",\"protocolVersion\":\"ECv2\",\"signedMessage\":\"...\"}",
    "amount": 50.00,
    "currency": "CAD"
  },
  "cardData": {
    "address": {
      "postalCode": "M5V 2T6",
      "line1": "123 Main St"
    }
  }
}

Google Pay Fields

FieldTypeRequiredDescription
googlePay.payment_tokenstringYesRaw Google Pay ECv2 token
googlePay.amountnumberYesPayment amount (min 0.01)
googlePay.currencystringYes3-letter currency code (e.g., CAD)
cardData.address.postalCodestringNoBilling postal code
cardData.address.line1stringNoBilling address

All Endpoints

Merchant API (Authenticated)

MethodEndpointDescription
POST/{business_id}/payment_linksCreate payment link
GET/{business_id}/payment_linksList payment links
GET/{business_id}/payment_links/{id}Get link details
PUT/{business_id}/payment_links/{id}Update link
DELETE/{business_id}/payment_links/{id}Delete link
GET/{business_id}/payment_links/exportExport links
POST/{business_id}/payment_links/{id}/resendResend link / receipt
GET/{business_id}/payment_links/{id}/attemptsView payment attempts

3D Secure API (Authenticated)

MethodEndpointDescription
POST/{business_id}/ddd/initStart 3DS session & card lookup
POST/{business_id}/ddd/authenticateRun 3DS authentication

Customer API (Public)

MethodEndpointDescription
GET/payment_links/{id}/payView payment page
POST/payment_links/{id}/paySubmit payment

Query Filters (List)

ParameterTypeDescription
fromDatedateFilter links created from this date
toDatedateFilter links created up to this date
statusstringFilter by status: CREATED, PAID, EXPIRED
customInvoiceNumberstringSearch by invoice number
customerstringSearch by customer name, email, or ID
perPageintegerResults per page (default: 10)

Card Data Fields Reference

FieldTypeRequiredDescription
cardData.cardNumberstringYesFull card number (PAN)
cardData.monthstringYesExpiration month (01-12)
cardData.yearstringYesExpiration year
cardData.cvvstringYesCard verification value
cardData.nameOnCardstringYesCardholder name
cardData.saveCardbooleanNoSave card for future use
cardData.address.line1stringYesBilling address line 1
cardData.address.postalCodestringYesBilling postal / ZIP code

Error Handling

ScenarioHTTP StatusDescription
Validation error422Missing or invalid fields
Unauthorized401Missing or invalid Bearer token (merchant API only)
Link not found404Payment link ID does not exist
Already paid200Returns receipt data so the customer can view the receipt
Link expired200ok: false with expiry reason
Max attempts exceeded200Link is automatically expired after max failed attempts
Transaction declined200ok: false with decline reason from processor
Error Response Example
{
  "ok": false,
  "error": "Payment link not found",
  "message": "Payment link not found"
}

Notifications

EventChannelRecipientDescription
Link CreatedEmailCustomerAutomatically sent when a payment link is created
Link ResentEmailCustomerSent when merchant triggers resend
Payment SuccessfulEmailCustomer & MerchantConfirmation with receipt when payment is approved
📧

SMS delivery is also supported. Merchants can share payment links via SMS through the dashboard or API.