Skip to main content
Every change here is backwards compatible unless an entry says otherwise. Breaking changes ship under a new Reap-Version, described in Versioning & Compatibility.

Production default rate limit is higher

The default production limit is now 600 requests per minute and 500,000 requests per day. The per-second limit stays at 20, and the tighter limits on card issuance, card operations, and identity verification are unchanged.

User applications return rejection labels

The application object on a user now carries rejectionLabels, a list of the reject codes from the compliance review, such as EXPIRATION_DATE or SELFIE_MISMATCH. It is set when the status is REJECTED or RETRY_REQUIRED and null otherwise.The list of codes can grow, so handle values you do not recognize. The codes are for your own use: do not show them to the end user.

Statements can end yesterday

A statement period can now end yesterday once that day’s card transaction data is final, from 10:00 UTC. Before then the latest end date is the day before yesterday.Timestamps in statement files now carry milliseconds, for example 2026-07-14T09:21:07.000Z. If you parse them with a fixed format, allow the fractional part.

Card creation returns 400 for unsupported residence countries

For project on KYC_ATTESTATIONS verification method, if the cardholder lives in a country where cards cannot be issued, Create card returns a 400 CARDHOLDER_COUNTRY_NOT_SUPPORTED error. It previously returned a 500.

Universal KYB addresses require line2

When you verify a company with Universal KYB, both the registered and operating addresses must include a non-empty line2. A pack without it is rejected.

Dispute refunds credit the cardholder, including prorated fees

When a dispute reaches REFUNDED, the dispute resource and CARD_DISPUTE_STATUS_UPDATED carry refundedAmount: { value, currency }. It is null until the case settles.refundedAmount is the cardholder credit: the network refund plus a proportional share of FX markup and ATM variable fee. The per-withdrawal ATM fee stays charged. The credit can be less than the disputed amount.The same credit is appended to the disputed card transaction as a new DISPUTE_REFUND event, delivered in CARD_TRANSACTION_UPDATED. It moves amount.refunded and amount.current like a merchant REFUND. If you keep the cardholder’s balance, as in External authorization, post the credit from that event and not from the dispute webhook, or it is booked twice.Transaction event type gains the DISPUTE_REFUND value. If you switch on event types, handle it like REFUND.

Filing a dispute no longer requires a cardholder signature

This is a breaking change. A filed dispute is created as RECEIVED and Reap takes the case from there. requiresCardholderSignature is gone from the dispute resource, PENDING_SIGNATURE is gone from the status list, and POST /disputes/:id/signature-link is removed. There is no replacement endpoint.

Companies can be verified with Universal KYB

If your project is set up for Universal KYB, you can submit business verification you have already completed instead of sending the company through a hosted session. Send the verified business pack and supporting documents, then submit the application for Reap to review.Company applications now include a nextAction that lists the documents still needed, or tells you to submit. Reap sends COMPANY_STATUS_UPDATED when the review finishes. Managed KYB works as before, and nextAction is null for it.Companies also have a new ACTION_REQUIRED status, which means Reap needs more information.

Universal KYB companies can be tested in sandbox

Simulate company status approves, rejects, or asks for action on a submitted Universal KYB application, and sends the same COMPANY_STATUS_UPDATED webhook as a real review. Simulating before the application is submitted returns SIMULATION_INVALID_STATE.
  • Reset company application returns a sandbox application to pending submission and keeps the pack and uploaded documents, so you can submit again

You generate the key pair for encrypted card details

For Encrypted retrieval in production, you generate the RSA key pair (2048 bits or larger) and send only the public key to your implementation manager. Reap does not generate or hold the private key.

Checkouts reject a malformed quote ID and state retry timing

Create checkout returns 422 when quoteId is not a valid UUID, before it reaches the merchant. Checkout validation failures return AGENTIC_REQUEST_REJECTED with the quoteId or enrollmentId that caused them.When a quote or checkout is temporarily unavailable, the 503 response has its own error code, QUOTE_TEMPORARILY_UNAVAILABLE or CHECKOUT_TEMPORARILY_UNAVAILABLE, and a Retry-After header with the number of seconds to wait.
  • Create quote documents the quote 503 response and its header

Card transaction fee rows show the fees Reap charged you

Card transaction fees statement rows add US dollar columns for each fee Reap charged you, from authorizationFeeUsd to atmNonFinancialFeeUsd. Each column matches a line on your invoice.Rows with no transaction event, such as a wallet provisioning or a 3DS authentication, now fill in cardId, cardLast4, and accountId when the card is known.

Quote a checkout URL from your own product discovery

Create quote accepts either product variant ids or a checkout URL that your application constructs. Checkout URLs can retain your attribution parameters. The request also accepts an optional offerCode for either quote source.

Quote errors state how to correct the request

Create quote errors now identify checkout URLs that cannot be used, unavailable card payment, invalid or expired offer codes, and quotes that the merchant cannot fulfill. Select shipping option errors also state when you must create a new quote or when the quote can no longer change.

Quote retries preserve each attempt

Reap makes one merchant request for a quote attempt. Reusing the same idempotency key replays the first response, including 503. A new key starts a new attempt. See Idempotency for retry guidance.

Card transaction merchants include an acceptor ID

Card transactions and the CARD_AUTHORIZATION_REQUEST webhook now include cardAcceptorId on merchant: the ID the merchant’s acquirer assigns, unique only within that acquirer, and null when the network does not provide one. Match the same merchant across transactions with cardAcceptorId, name, country, and mccCode together. merchant.id is a different value on every transaction even for the same merchant, so it no longer serves that purpose.

Agentic API errors identify what went wrong

Enrollments, quotes, and checkouts under /agentic now return specific error codes instead of only the generic AGENTIC_REQUEST_REJECTED and AGENTIC_RESOURCE_NOT_FOUND. An expired quote returns QUOTE_EXPIRED, an unknown enrollment returns ENROLLMENT_NOT_FOUND, a sold-out variant returns VARIANT_UNAVAILABLE, and a reused idempotency key returns IDEMPOTENT_PARAMETER_MISMATCH or IDEMPOTENCY_REQUEST_IN_PROGRESS, among others. The generic codes still cover any case without a specific one, so existing error handling keeps working.

Checkouts can be completed instantly in sandbox

Create checkout accepts a new X-Simulate-Checkout: COMPLETED header in sandbox, which returns the checkout as COMPLETED without waiting on the underlying payment. Production requests reject the header.

Idempotent retries of an empty response no longer fail

Retrying a call with the same idempotency key against an endpoint that returns no body used to answer with a 500 on replay. It now replays the original empty response, the same as any other idempotent retry.

Cross-currency card-transaction simulations require the original amount

Simulating an authorization, clearing, reversal, refund, decline, or 3DS challenge now requires originalAmount when the event lands on a transaction whose original currency differs from your billing currency, returning the existing SIMULATION_INVALID_STATE error if it is missing. The amount, currency, and timestamp recorded for the event now always match what the transaction webhooks report for it.

Encrypted card details can use RSA-OAEP with SHA-256

Reveal PAN can return encryption: "RSA_OAEP_SHA256" alongside the existing RSA_OAEP_SHA1. The value follows the public key registered for your program, so decrypt with the hash it names rather than a fixed one. Keys registered from now on use SHA-256.

Sandbox refunds require a matching cleared transaction

Simulate refund now checks that the transaction it acts on can actually be refunded. Passing transactionId requires that transaction to have been authorized before it cleared, so one created by offline or direct clearing cannot be refunded. Omitting transactionId for a standalone refund now requires the card to already have an authorized and cleared transaction in the refund currency, since the refund takes its merchant and currency from that transaction instead of generating them at random. Either case that fails returns the existing SIMULATION_INVALID_STATE error.

Company deactivation is reported separately from KYB status

Company resources now include isDeactivated. It is true while the verification provider has deactivated the company, and it is independent of status. The last KYB outcome stays on the company. Spend is stopped by moving the company to RESTRICTED. The company remains readable by id so you can still resolve users and cards that point at it.COMPANY_STATUS_UPDATED carries the same field.Related person resources now include isActive. It is false when the person has been archived.Get related person still returns an archived person. List related persons omits them unless you pass includeArchived=true.

Statements itemise the fees Reap billed you

Request a statement for a period and Reap produces a CSV of every fee event it billed you for, one row each. The rows carry the transaction, the fee category, and the amounts behind each one.Ask for the whole file or name the columns you want. Files are prepared in the background and stay available for 180 days.

API keys can be restricted to a set of IP addresses

A key can be limited to a list of IPv4/IPv6 addresses or CIDR ranges. Once a list is set, a request from any other address is rejected, including one where Reap cannot determine the caller’s address at all.
  • Authentication documents the allowlist and the 403 API_KEY_IP_NOT_ALLOWED error it returns

Account balances report fiat credits alongside crypto

Get account balance adds assets.fiat, the amount credited to the account by bank transfer. Only the master collateral account can be funded that way, so every other account keeps reporting null there.Get account assets itemizes the same credit as a FIAT entry alongside the crypto rows, valued at par in the account’s currency.

Card shipment status webhooks include the cards in the shipment

CARD_SHIPMENT_STATUS_UPDATED now carries the same cards[] array as Get shipment. Each card includes cardId and productionStatus, so you can map a status change to the cards in the shipment without a follow-up request.

Sandbox authorization can raise a detected fraud alert

Simulate authorization and Simulate 3DS authorization accept optional triggerFraudAlert: true. That creates the charge and asynchronously raises a detected fraud alert you can respond to or list like production.

Sandbox simulations carry your program’s cardholder fees

Simulated authorizations, clearings, reversals, and refunds are priced like live transactions. The fees on a simulated transaction reflect your program’s rates, the ATM tier resolved from the merchant country, and any override set on the account. The amount you simulate is the merchant amount and the fees are charged on top of it.Sandbox fees were always zero, so an integration that asserted fees.atm and fees.fx are 0 on a simulated transaction needs to update that expectation. A simulation that omits channel now runs as ECOMMERCE instead of picking a channel at random, so a same-currency purchase stays free of fees unless you ask for an ATM withdrawal.

Cardholder fees are configurable per program and per account

The FX markup and the ATM withdrawal fees your cardholders pay are no longer fixed. Every program carries a default rate per fee type, and you can override any of them for a single account. ATM fees are split into a domestic and a cross-border tier, each with a rate-based and a fixed component. See Cardholder fees.Set your program’s default fees in the dashboard before launching in production: only an organization Admin can change them, and only from the dashboard.

Cards always report a design id

cardDesignId no longer returns null. Reap backfilled the design on every card issued before it started recording one.

A card can only run one sandbox simulation at a time

Simulate authorization and Simulate decline now return a 409 with SIMULATION_IN_PROGRESS when a simulation is already running for the card. Wait for the first one to finish, then retry.

Agentic Payments sandbox setup includes test cards and a one-time password

Setup lists card numbers you can enter on the hosted card entry page to run a full sandbox checkout, plus the fixed one-time password the verification step accepts.

Singapore gets a dedicated API hostname

Singapore sandbox and production now have their own hostnames, sg.sandbox.api.reap.global and sg.prod.api.reap.global, matching the pattern Mexico already uses. sandbox.api.reap.global and prod.api.reap.global keep working as aliases.

Enrollment and mandate owners are identified by type and id

An Agentic Payments owner now carries an id instead of a reference. It can also be a REAP_USER, alongside the existing CLIENT_REFERENCE. A REAP_USER owner is derived from the cardholder of an enrolled Reap card. You never send it on a request.List enrollments filters on ownerId, which replaces ownerReference. The filter is now required, so a list is always scoped to one owner.

Enrollments are created per card source, and checkouts charge a stored enrollment

Create enrollment request and response now depend on source:
  • An existing Reap card, enrolled directly
  • A BIN-sponsor card, enrolled directly
  • A hosted page that captures a new card
Enrolling an unknown Reap card returns a new AGENTIC_CARD_NOT_FOUND error.Create checkout now takes the enrollmentId of an ACTIVE enrollment and charges that enrollment’s stored card and owner. It no longer accepts an inline owner. A checkout can also reach an EXPIRED status, reported by Get checkout.

Card authorization requests carry a transaction id

CARD_AUTHORIZATION_REQUEST now includes transactionId, the id of the transaction the authorization belongs to. It matches id on the transaction webhooks that follow it.

KYC attestations require a second address line

An address on a KYC attestation must now include a non-empty line2. Use the district, area, or building name if the address has no natural second line. An attestation with an empty or missing line2 now fails at the attestation call instead of later, at card issuance.

Cards report the design they were issued with

Get card and List cards now return cardDesignId. For a physical card this is the design on the card record, which can differ from the design on the shipment that produced the plastic. cardDesignId is null on cards issued before Reap started recording the design.

A product’s variant can be resolved from its option choices

Get product details now returns a product’s option axes instead of resolving them to a variant itself. When a product has options, pass the chosen option ids to Resolve variant to get the variant id a quote accepts.Get quote retrieves a quote you already created, so you no longer have to hold onto the response from Create quote to check its state later.

Sandbox card shipment and activation simulations no longer fail

Checking on a simulated shipment while it was between statuses, and activating a physical card after simulating its delivery, could both return an unexpected server error in sandbox. Both now complete normally.

Encrypted card details retrieval is documented in the API reference

Reveal PAN returns a card’s PAN, CVV, and expiry as an encrypted payload, for PCI-scoped partners Reap approves for direct card-data access. The endpoint and its integration guide no longer require a private link to find.The capability itself has not changed: it stays off by default until Reap reviews your compliance status.

ATM withdrawal fees can include a flat per-withdrawal component

The atm amount in a card transaction’s fees can now carry a flat fee on top of the existing rate-based markup, if your project’s pricing includes one. A refund of a settled withdrawal never carries the flat component, since the network cost behind it was already incurred.

Policies can restrict or limit push-to-card transactions

VISA_DIRECT is a channel a channel-restriction, spend-limit, or authorization-count-limit policy can now name, alongside POS, ECOMMERCE, and ATM.

Funds can be withdrawn from an account to an external address

You can move tokens out of a User-Funded account’s wallet to any address you name. Initiate crypto withdrawal reserves the funds and opens a signature window. The wallet owner signs a payload from Mint signing payload, and you hand the signature to Submit withdrawal signature. Reap covers the network fee and charges a flat fee per chain, taken out of the amount you request.Subscribe to CRYPTO_WITHDRAWAL_CREATED and CRYPTO_WITHDRAWAL_STATUS_UPDATED to follow one to completion. You can also read one with Get crypto withdrawal, or cancel one that is still waiting for a signature. Withdrawals appear in the activity feed.See Withdrawing Funds.

Account assets report what can be withdrawn per chain

Each chain in the assets endpoint now reports withdrawable, the largest amount you can request on that chain, and withdrawalFee, what a withdrawal there costs. Outstanding card spend is already netted out of withdrawable, so you can show a user a figure they can act on.See The withdrawable cap.

Account ownership is chosen per account

Create account accepts an optional ownerType (USER or COMPANY). It defaults to USER when omitted. Company-owned accounts are only available in corporate programs and return 400 COMPANY_ACCOUNT_NOT_ALLOWED in consumer programs. Account ownership is no longer a project-level setting.See Program Mode and Accounts.

Deleting a user deletes their cards

Delete user deletes every card the user holds, instead of just blocking them. Deletion is permanent. The user’s accounts stay open, since they can still hold value or card debt to settle.

Creating a user no longer needs terms acceptance

Create user no longer accepts or requires termsAcceptance. Drop the field from any request that still sends it.

Card shipment status can be simulated in sandbox

Simulate shipment status drives a submitted shipment through production and delivery in sandbox. Watch the change arrive through CARD_SHIPMENT_STATUS_UPDATED.
  • Shipping covers card production and delivery tracking

Users can be looked up by your own identifier

Create user accepts an optional externalId, your own identifier for the user. It must be unique among your active users, so a request that reuses one is rejected with EXTERNAL_ID_ALREADY_EXISTS rather than creating a duplicate. Deleting a user releases the value for reuse.Pass it to List users as externalId to resolve your identifier back to a Reap user.

Fiat deposit simulation takes the currency you send, not a conversion pair

Simulating a fiat deposit now takes a required currency, the currency of the simulated transfer. It replaces the optional originalAmount and originalCurrency that previously simulated a converted transfer.The currency must be the one your card program bills in. Any other is rejected with SIMULATION_UNSUPPORTED_CURRENCY, which lists the currencies the project accepts. A sandbox call that still sends originalAmount or originalCurrency now fails validation.

Deposit addresses name the assets they accept

Each deposit address now names the assets it accepts. Each item uses the same symbol, name, decimals, and logoUri fields used elsewhere for asset metadata, plus the assetId to deposit against.A deposit of anything else fails with ASSET_NOT_ACCEPTED. Read the list rather than hardcoding one, since what a project accepts is a subset of what the platform supports.List responses stay lean and omit it. name and logoUri are best-effort and may be null, so render a fallback for both.

Sumsub Token Sharing decisions now arrive by webhook

Importing a Sumsub applicant share token no longer approves the user synchronously. A successful import now moves the user to IN_REVIEW.The decision, APPROVED, REJECTED, or RETRY_REQUIRED, then arrives on the same USER_APPLICATION_STATUS_UPDATED webhook used by Managed KYC.A failed import can now leave the user at RETRY_REQUIRED as well as NOT_STARTED.

Choose the account owner type at creation

Creating an account now takes an explicit ownerType, USER or COMPANY, instead of inferring it from the project.It defaults to USER. ownerId is a user ID or a company ID to match. Requesting COMPANY outside a corporate program now fails with COMPANY_ACCOUNT_NOT_ALLOWED.

Fund the master collateral account by bank transfer

Get bank details returns the beneficiary name and address, the account number, the bank name and address, the SWIFT code, and the domestic bank and branch codes for wiring funds into the master collateral account, along with a reference to quote on the transfer. It applies to Program-Funded projects enabled for bank transfers. FIAT_DEPOSITS_NOT_ENABLED means the project has not been enabled for it.See Funding via Bank Transfer.

Card shipping can be disabled for a project

Submit shipment returns 403 CARD_SHIPPING_NOT_ENABLED when physical card shipping is not enabled for the project.See Shipping.

Company simulation rejects restricted countries

Simulate company status now rejects country, registeredAddress, and operationalAddress values for a country that cannot be used for card issuance, such as KP, when simulating ACTIVE.See Getting started with KYB.

Cards can be blocked and unblocked directly

You can block a card and unblock it when the block can be lifted. A block is a hard stop, separate from freezing it.blockLiftable on the card resource tells you whether unblock will work before you call it.frozen reports a freeze that a block is hiding from status.blockReason.type on a blocked card can be CLIENT_REQUESTED.

Card management stays available when an account is restricted

Card operations no longer fail with ACCOUNT_NOT_ACTIVE when the linked account is restricted.blockReason.type can no longer be ACCOUNT_RESTRICTED. Restriction only affects transaction authorization, tracked on the account.

File a dispute on a cleared card transaction

You can dispute a cleared card transaction and have Reap take the case to the card network.Send the transaction ID and a reason. Reap derives the card and cardholder from the transaction, along with its currency.Some reasons need a signed statement from the cardholder before the case can move forward. Subscribe to CARD_DISPUTE_STATUS_UPDATED for the outcome.

Fiat deposits are now available over the API

You can read a fiat deposit credited to an account. The response includes the amount as received by the bank and the amount actually credited.Those two differ when the transfer was converted on the way in.In Program-Funded programs you can simulate a deposit in sandbox. Subscribe to FIAT_DEPOSIT_CREATED for new deposits.Fiat deposits also appear in the activity feed as FIAT_DEPOSIT.

The activity feed can return more than one activity type at once

type on the activity feed accepts a comma-separated list. type=CRYPTO_DEPOSIT,CARD_TRANSACTION returns deposits and card transactions together in one ordered, paginated feed.Every other filter narrows within its own activity type instead of restricting the feed to it.cardId=<id> alone still returns the account’s other activity alongside that card’s transactions. Combine it with type=CARD_TRANSACTION to see the card’s transactions by themselves.

Master deposits can be charged a deposit fee

Deposits into a master account can carry a fee, set per project and agreed with Reap. The fee comes out of the deposit.Each deposit reports what it was charged in feeAmount, in the same token as amount. A project with no fee reports 0.Deposits into user accounts are never charged and report null.
  • Deposit fee explains when a master deposit is charged

Simulate an authorization with a 3DS challenge

You can run the whole challenge flow in sandbox for cards using 3dsChallengeMethod: WEBHOOK.The simulation sends CARD_3DS_CHALLENGE_CREATED without creating a transaction. Approving one creates the transaction, rejecting it does not.

Responding to a closed 3DS challenge returns a specific error

A closed challenge returns a specific error if it has already been answered or has expired.

Fraud alerts can be handled through the API

Reap raises an alert on a transaction it suspects is fraudulent. You can also report a past transaction as fraud yourself.You can list alerts and fetch one, then respond to confirm or decline. Confirming an alert or reporting a transaction as fraud blocks the card and sends CARD_STATUS_UPDATED with blockReason.type: FRAUD_ALERT_CONFIRMED.CARD_FRAUD_ALERT_CREATED fires when an alert is raised. CARD_FRAUD_ALERT_STATUS_UPDATED fires when its status changes.An alert that nobody answers in time expires on its own.