Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.rinne.com.br/llms.txt

Use this file to discover all available pages before exploring further.

Use this guide to implement CREDIT_CARD and DEBIT_CARD transactions with the Rinne Core API.
Rinne officially supports both 3DS strategies for card payments: session-first and transaction-first.

Transaction endpoints (self vs merchant)

Prerequisites

  • Active affiliation for card payments.
  • ECOMMERCE capture enabled for online transactions.
  • One unique request_id per payment attempt.
  • Encrypted card values from rinne-js secure components.
Do not collect raw PAN/CVC in custom inputs. Forward encrypted values from Card Element only.

Required transaction shape

provider
string
required
Payment provider configured for the affiliation.
request_id
string
required
Idempotency key for creation.
amount
integer
required
Amount in cents.
capture_method
string
required
Use ECOMMERCE for card-not-present checkout.
payment_method
string
required
CREDIT_CARD or DEBIT_CARD.
card_data
object
required
Card payload for card transactions.

Card data rules

  • Send exactly one of card_data.number or card_data.network_token.
  • Send expiry_month (MM) and expiry_year (YYYY).
  • Send cardholder_name with the name as it appears on the card.
  • Send last_digits with the last 4 digits of the card number (must be exactly 4 digits).
  • For authenticated/tokenized flows, provide cryptogram directly or via three_d_secure_session_id injection.
  • For wallet tokenized flows, include wallet_type (APPLE_PAY or GOOGLE_PAY).
Do not send both number and network_token in the same request.

3DS challenge strategy flags

TransactionCreateRequest supports two optional card-only flags:
require_3ds
boolean
When true, card transaction creation always goes directly to AWAITING_3DS. Provider authorization is deferred until /authenticate is called with an authenticated 3DS session.
refuse_on_challenge
boolean
When true, any path that would require a challenge (risk-triggered or soft-decline-triggered) is refused immediately (REFUSED) instead of transitioning to AWAITING_3DS.

Why these flags are useful

FlagImmediate status behaviorWhat your backend still handlesWhat this avoids
require_3dsAlways creates card transactions in AWAITING_3DSCreate 3DS session, complete challenge when required, and call /authenticateImplementing a second session-first architecture only to enforce 3DS policy
refuse_on_challengeReturns REFUSED with status_reason=CHALLENGE_NOT_ALLOWED when challenge would be requiredHandle refusal/retry paths onlyImplementing challenge UX and pending AWAITING_3DS operational queues for that scope
With require_3ds, organizations that already run transaction-first can enforce 3DS for all or selected transactions without adding a separate session-first policy path. The transaction enters AWAITING_3DS immediately, which is the status you already handle in this flow. With refuse_on_challenge, challenge-triggered flows do not enter AWAITING_3DS; they stop immediately as REFUSED, so your operation fails fast and carries no challenge-handling workload.
refuse_on_challenge changes only challenge-triggered paths. Transactions that do not require challenge continue normal provider processing.

CHALLENGE_NOT_ALLOWED status reason

When refuse_on_challenge is true and a challenge would be required (risk-triggered or soft-decline-triggered), transaction response uses:
  • status = REFUSED
  • status_reason = CHALLENGE_NOT_ALLOWED
require_3ds and refuse_on_challenge are mutually exclusive. Requests with both set to true must be rejected.

Policy granularity

Because these flags are part of each transaction request, you can apply policies with fine control:
  • Per merchant (choose behavior by merchantId in your backend routing).
  • Per payment flow (for example, mobile app vs web checkout).
  • Per transaction segment (risk tier, issuer group, customer cohort, high-value purchases).

Example: standard card transaction

cURL
curl -X POST 'https://api-sandbox.rinne.com.br/core/v1/transactions' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "provider": "RINNE",
    "request_id": "order-card-0001",
    "amount": 25990,
    "currency": "BRL",
    "capture_method": "ECOMMERCE",
    "payment_method": "CREDIT_CARD",
    "installments": 1,
    "card_data": {
      "number": "ev:encrypted:card_number",
      "cvv": "ev:encrypted:cvc",
      "expiry_month": "12",
      "expiry_year": "2028",
      "cardholder_name": "Maria Santos",
      "last_digits": "1111"
    }
  }'

Example: force transaction-first 3DS

cURL
curl -X POST 'https://api-sandbox.rinne.com.br/core/v1/transactions' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "provider": "RINNE",
    "request_id": "order-card-0002",
    "amount": 25990,
    "currency": "BRL",
    "capture_method": "ECOMMERCE",
    "payment_method": "CREDIT_CARD",
    "card_data": {
      "number": "ev:encrypted:card_number",
      "cvv": "ev:encrypted:cvc",
      "expiry_month": "12",
      "expiry_year": "2028",
      "cardholder_name": "Maria Santos",
      "last_digits": "1111"
    },
    "require_3ds": true
  }'
Example response
{
  "id": "tx_123456789",
  "status": "AWAITING_3DS",
  "amount": 25990,
  "currency": "BRL"
}

Example: fail fast when challenge is not allowed

cURL
curl -X POST 'https://api-sandbox.rinne.com.br/core/v1/transactions' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "provider": "RINNE",
    "request_id": "order-card-0003",
    "amount": 25990,
    "currency": "BRL",
    "capture_method": "ECOMMERCE",
    "payment_method": "CREDIT_CARD",
    "card_data": {
      "number": "ev:encrypted:card_number",
      "cvv": "ev:encrypted:cvc",
      "expiry_month": "12",
      "expiry_year": "2028",
      "cardholder_name": "Maria Santos",
      "last_digits": "1111"
    },
    "refuse_on_challenge": true
  }'
Example response
{
  "id": "tx_123456789",
  "status": "REFUSED",
  "status_reason": "CHALLENGE_NOT_ALLOWED"
}

Card transaction lifecycle highlights

StatusMeaningTypical next action
PROCESSINGAuthorization in progressWait for webhook/result fetch
AWAITING_3DS3DS authentication requiredComplete 3DS and call /authenticate
AUTHORIZEDAuthorized but not capturedFollow capture policy
APPROVEDPayment acceptedFulfill order
REFUSEDPayment declinedRetry with new attempt/payment method

Retry and idempotency

  1. Generate one request_id per attempt.
  2. Reuse same request_id only for safe retries of the same attempt.
  3. Use a new request_id for a new customer attempt.

Refunding card transactions

Send refund_amount equal to the remaining refundable amount for a full refund, or any smaller amount for a partial refund (subject to the rules below).
cURL
curl -X POST 'https://api-sandbox.rinne.com.br/core/v1/merchants/MERCHANT_ID/transactions/TRANSACTION_ID/refunds' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "refund_amount": 25990,
    "refund_reason": "CUSTOMER_REQUEST",
    "description": "Full refund - same day"
  }'

Card refund rules

Two independent acquirer rules apply to every card refund. Both are pre-validated server-side and surface as HTTP 400 VALIDATION_ERROR before any provider round-trip.
One successful refund per card transaction. Once a CREDIT_CARD or DEBIT_CARD transaction has a refund in COMPLETED status, the acquirer treats it as terminally refunded. Any additional refund request — partial or full — is rejected with HTTP 400.Plan the refund amount up front: if you need to return funds in pieces, the first successful refund must cover the full remaining amount you intend to return. Refunds in FAILED or CANCELLED status do not count toward this rule, so you can submit a new attempt after a failed one.
Same-day partial refunds are not allowed. When a refund request lands on the same calendar day as the transaction’s approved_at (D0), only a refund for the full remaining refundable amount is accepted. Partial refunds are allowed only from the next calendar day (D+1) onward.
The acceptance matrix on a transaction approved with approved_amount = 10000 and no prior COMPLETED refund:
DayRefund amountResult
D0 (same day)10000 (full)Accepted (outcome resolved per response semantics below)
D0 (same day)5000 (partial)Rejected — 400 VALIDATION_ERROR: Partial refund on the same day as the transaction is not allowed by the acquirer; submit the full remaining amount or wait until D+1
D+1 or later5000 (partial)Accepted (outcome resolved per response semantics below)
D+1 or later10000 (full)Accepted (outcome resolved per response semantics below)
Once any refund on the transaction reaches COMPLETED, every row above is rejected with HTTP 400 (Card transaction has already been refunded; the acquirer does not allow additional refunds), regardless of the day or whether the new request is partial or full.

Card refund response semantics

Card refunds resolve synchronously whenever the acquirer returns a definitive answer:
  • A successful cancel returns refund.status = COMPLETED and the transaction status becomes REFUNDED (full) or PARTIALLY_REFUNDED (partial).
  • A definitive provider rejection (for example, an acquirer business decline) returns refund.status = FAILED. Failed card refunds are terminal and are not retried — submit a new refund request to try again.
  • An uncertain outcome (acquirer 5xx or network timeout) triggers an inline status query against the acquirer. If that resolves the outcome, you still get COMPLETED or FAILED on the same call. Otherwise the refund moves to TIMEOUT and is reconciled asynchronously.
  • A PENDING_REFUND transaction status on a card transaction means the request was accepted but did not produce a definitive answer; we will retry the (idempotent) cancel.
For the full set of refund rules, statuses, and the cancel-pending-refund endpoint, see Refunds in the Transactions concept.

Integration with rinne-js

Your card integration is production-ready when you correctly handle PROCESSING, AWAITING_3DS, APPROVED, REFUSED, and the CHALLENGE_NOT_ALLOWED status reason.