RealPayment External API
API version 0.13.7. Document-provider permissions require an explicit grant from the account owner.
Document-provider permissions and business branding
Internal management routes use the owner's Firebase Bearer token. External routes use X-API-Key, and document-provider access also requires explicit owner-granted scopes. The business owner is resolved from the key; clients cannot select another owner.
The existing API-key form can grant documentProviderScopes explicitly on POST /api/api-clients; omitting the field grants neither provider permission. PUT /api/api-clients/{clientId} requires expectedProviderScopesVersion when documentProviderScopes is supplied and saves the client fields and permission change atomically. The new secret is revealed once to the owner on creation. Legacy keys receive no automatic provider permissions.
The signed-in owner grants an owned ordinary client access through PUT /api/api-clients/{clientId}/document-provider-scopes with scopes and the current documentProviderScopesVersion as expectedVersion (0 before a version is recorded). Only documents.providers.read and documents.providers.write are replaced; other scopes are retained. An empty scopes array revokes both. A stale version returns 409. Dedicated SaaS billing clients cannot receive these provider scopes.
GET /external/document-provider requires documents.providers.read and returns activeProvider, configVersion, readinessSource=stored_evidence, safe CardCom readiness/blockers, and recorded capabilities. PUT /external/document-provider/selection requires documents.providers.write, provider=internal or cardcom, the current configVersion as expectedVersion, and X-Idempotency-Key. The key must contain 16–160 ASCII letters, digits, underscores, dots, colons, or hyphens. Test-mode clients can read with the read scope; provider changes return 409. Dedicated SaaS billing clients cannot use either external provider route.
Retry a selection using the same key and payload. A completed request returns the original selection and operationId with replayed=true, plus current settings, without another switch. Current settings may differ after a later change; replay does not restore the old selection. A different payload with the same key, a stale version, or unready CardCom returns 409. A new intentional change needs fresh settings and a new key. Existing payments and documents keep their original issuer. These routes do not create a provider account, issue a document, or charge money.
PUT /external/business-profile accepts logoUrl as an HTTPS URL of at most 2048 characters without embedded credentials, or null to remove the logo, plus six-digit HEX brandColor and secondaryColor. Branding is global to the business and applies to RealPayment's payment page. There are no per-link branding overrides, and the CardCom iframe keeps its provider-controlled appearance.
POST /api/document-provider/connect uses the owner's Firebase Bearer token and the current configVersion as expectedVersion. For a first connection with saved CardCom credentials, it prepares and verifies a private binding using an existing authenticated, signed CardCom document for that terminal. The signed issuer header and tax ID must match the business legal identity; the display brand is separate from the legal name. Registration collects the legal name explicitly, and an individual dealer may confirm a suggested personal name. Company legal names must be supplied explicitly. Document type, currency, payment method and company scope remain gated by evidence. Automatic-document suppression is established from the CardCom LowProfile contract, in which Document is optional, together with verification that the application removes Document in the guarded payment payload. A prior paid J4 transaction without a document is not a prerequisite. This contract inference is distinct from observing a real subsequent charge and document issuance. Identity or tax-ID mismatches remain blocked and are explained separately. Existing bindings retain readiness checks, and report access alone does not grant issuance readiness. This operation does not open a CardCom merchant account, issue a document, charge money or notify customers. Read current settings after an uncertain response. External provider selection uses an already verified binding and does not invoke this owner-only setup.
Monthly subscriptions: registration, status, and cancellation
קישור לאישור הוראת קבע — Recurring payment approval link
זהו השם של הפעולה שמציגה במסך “הקישור מוכן — ממתין לאישור הלקוח”.
External API: Payments → Create a payment link, using POST /external/create-payment with X-API-Key. Internal UI: Recurring Payments → Creating a link to confirm a subscription from the internal interface, using POST /api/create-payment with the owner's Firebase Authorization: Bearer token.
For monthly billing, send recurringData.isAutoRecurringPayment=true, frequency=monthly, interval=1, and the agreed future startDate. Set totalBills=0 for no charge-count limit; an agreed endDate still applies.
initialCharge=on_approval: חיוב ראשון לאחר אישור מאומת ושמירת הכרטיס להמשך.startDateהוא החיוב האוטומטי הבא. פעולת CardCom:ChargeAndCreateToken.initialCharge=on_scheduled_date: שמירת הכרטיס לאחר אישור מאומת, ללא חיוב עכשיו.startDateהוא החיוב הראשון בעתיד. פעולת CardCom:CreateTokenOnly.
operationState=link_created confirms link creation only. It does not confirm customer approval, a successful payment, or subscription activation. After customer approval, read GET /external/payment-status/{paymentId} and the owned recurring status through GET /external/recurring-payments/{id}; the internal UI uses GET /api/recurring-payments. Activation requires a verified provider result and a valid stored token.
When approvalLinkExpiresAt is returned for a managed local approval link, it is RealPayment's deadline for the pending approval. CardCom controls its form validity separately and may expire it sooner. The local deadline does not extend or reopen the CardCom form.
You can create a subscription with a standard card, read its status and history, and stop future charges. The external API uses X-API-Key. The internal API uses Authorization: Bearer with the business owner's Firebase ID token. These credentials are not interchangeable.
To register without charging immediately, send recurringData with isAutoRecurringPayment=true, frequency=monthly, interval=1, initialCharge=on_scheduled_date, and a future startDate. Use POST /external/create-payment externally or POST /api/create-payment internally. The amount is charged on each future cycle, not at registration. totalBills=0 continues until cancellation.
Send paymentUrl to the customer. X-Idempotency-Key is required when creating links in the app or portal and when using deferred registration through the API. Reuse the same key and request body for retries. A missing key returns 428 before a record or provider call is made. A safe key for both flows has 16–128 ASCII letters, digits, hyphens, or underscores. External deferred registration requires a live key, zero commission, and the terminal's token module. It is unavailable with a test key or the SaaS v1 contract.
A link alone does not prove activation. After customer approval, check GET /external/payment-status/{paymentId} and GET /external/recurring-payments/{id} or the recurring list. Internally, use GET /api/recurring-payments. Activation requires a verified token and provider result. Deferred registration begins with zero charges, revenue, or financial documents.
For deferred registration, startDate is the first charge date. With on_approval, it is the next charge after the initial approval charge. Choose tomorrow or later in Israel time. If approval arrives late, the date moves to a future cycle without a retroactive charge. Collection runs in the daily 09:00 schedule; a personal charge time or exact execution time is not guaranteed.
To stop a standard recurring payment, use PATCH /external/recurring-payments/{id}/status with status=cancelled, or internally POST /api/recurring-payments/{id}/status. This stops new charges in RealPayment's token flow; it does not refund past charges. chargeInFlight=true means a charge already sent to the provider may still finish. Cancelled or completed instructions cannot be reopened.
If billingMode=cardcom_recurring, local cancellation is refused because the instruction must also be cancelled at CardCom. A dedicated SaaS billing client instead uses cancel-at-period-end with a contract version and idempotency key; PATCH status is unavailable for that client. Read capabilities before acting and use reconcile to inspect an uncertain outcome without creating another charge.
The history summary shows verified collections less refunds, by currency, and flags incomplete data. It is not confirmation of a bank credit. Document and delivery automations are configured per instruction in its detail view and are off by default. Delivery remains subject to settings and recipient consent.
Apple Pay and Google Pay are unavailable for subscription or token registration in this flow. Google Pay for a one-time payment is offered only on an enabled CardCom payment page. Apple Pay inside an iframe requires domain registration and verification with CardCom; an available verification file alone is not provider approval. This flow has no external Google Pay button or subscription wallet bridge.
An owned pending deferred registration can recover through GET /external/payment-status/{paymentId}. The provider-verified CreateTokenOnly operation and JParameter=2 distinguish token registration from a debit or hold; a response code alone is insufficient. The existing callback lease and atomic pipeline activate the already-approved future instruction, with no initial charge, revenue or financial document.
API credentials, documents, and safe retries
Use X-API-Key for external routes. Internal management routes use the signed-in owner's Firebase Bearer token and their existing account, session, and role checks. A dedicated SaaS billing client must be provisioned for its approved server-side policy and route scope; adding SaaS fields to an ordinary key does not grant these capabilities. test_only is not live provider approval.
For a receipt, send customerName, a nonzero amount, and description. A signature link requires documentId and signerName and supports an owned unsigned quote. Invoice-receipt creation requires a positive amount; items are optional. Item quantity must be positive and price may be zero. Use finite numbers or complete decimal strings, never values such as 12abc.
CardCom accounting issuance without a linked paymentId requires one stable document identity: Idempotency-Key, X-Idempotency-Key, or body.requestId. Keep the identity and body unchanged on retry; all identities supplied together must match. The document identity header is distinct from payment-link retry policy. Legacy internal document issuance has no equivalent durable replay guarantee.
If document issuance returns operationId, an unknown outcome, or safeToEdit=false, the signed-in owner can inspect its stored state with GET /api/document-provider/operations/{operationId} using a Firebase Bearer token. External API keys cannot use this management route. Keep the original identity and payload while the outcome is resolved. Creating another request identity can create another document. Document creation does not charge or refund money and does not by itself send a customer message. Dedicated SaaS clients retrieve existing payment documents through their supported document-read route.
For internal document-provider settings, use GET /api/document-provider with the owner's Bearer token. POST /api/document-provider/validate reads a CardCom report and records a connection check for an existing prepared binding; a successful read alone does not prove issuance readiness. PUT /api/document-provider/selection requires provider=internal or cardcom and the current configVersion as expectedVersion. CardCom must pass the release and readiness gates; stale versions, changed bindings, or open operations can return 409. These routes do not provision a provider account or change the issuer stored on historical payments or documents.
Payment-link creation accepts ILS and USD; omitting currency uses ILS. The server trims and normalizes its case. An unsupported currency returns 400 with INVALID_CURRENCY for a one-time payment or RECURRING_CURRENCY_UNSUPPORTED for a recurring request, before a payment record or provider call. A dedicated SaaS plan must also permit the selected currency.
For recurring links, totalBills counts charges and endDate includes the selected Israel calendar day. New charges stop at the first applicable count or date limit. An already dispatched provider result can still be reconciled after the agreement ends. Keep endDate unchanged when replaying the same creation request.
Refunds and document scope before new payments
One full or partial refund per completed payment is supported through POST /api/cardcom-refund with the signed-in owner's Firebase Bearer token. X-API-Key does not authorize this management route. Send the owned payments record ID as transactionId and its matching CardCom ID as cardcomTransactionId. Omit partialSum for a full refund, or send a positive amount of at most two decimal places no greater than the original amount. Omit allowMultipleRefunds or send false.
The original document issuer must be ready for the required correction before money is sent. A CardCom connection verified only for receipts, card payments and ILS remains restricted to that evidence. The connection message does not mean that correction or refund capabilities have been enabled. Existing payments keep their original captured issuer.
A 202 response with refundCompleted=true and canRetry=false confirms the money refund while local accounting still needs reconciliation. A 503 with REFUND_OUTCOME_UNKNOWN means the provider result is unresolved. A 409 can also block an unresolved previous attempt. Do not repeat the money request in these states, change its identity, or assume an expired lock makes it safe.
The CardCom financial refund does not generate a document by itself. Even a 200 response can carry a pending refundDocument or commissionRefund. POST /api/payments/{id}/refund-document continues the document for an already confirmed owned refund; it never sends another money refund. A verified provider decline returns REFUND_PROVIDER_DECLINED and canRetry=true; other errors do not imply permission to retry.
Before new payment-link creation and dispatch, direct or manual recurring charges, manual completed-ledger entries, and an expired checkout-link renewal, the guarded API checks the original binding's receipt, currency and payment-method scope. A card-only ILS receipt binding blocks new USD requests or incompatible ledger methods before recording or contacting the provider. Existing completed replays and historical internal issuers retain their recorded behavior. This release does not replace the separately frozen scheduled consumers; their asynchronous outcomes remain a separate verification boundary.
Document workspace, drafts and safe continuation
Use the signed-in owner's Firebase Bearer token for /api/documents-v2/context, /create and /drafts. These management routes do not grant an external X-API-Key capability. Existing external provider selection and scope contracts remain unchanged.
GET /api/documents-v2/context returns the actual business and provider limits. Supply paymentId for an owned source payment: the original issuer, amount, currency and customer remain tied to that payment. A ready CardCom connection verified for receipts, card payments and ILS does not permit invoice, bank, cheque or correction issuance without separate evidence. quoteIssuer describes the server-selected quote provider separately from the accounting issuer. CardCom quote readiness also requires the explicitly enabled separate customer-acknowledgment chain; readiness is configuration evidence, not live provider acceptance. A context failure preserves entered fields and blocks new creation until retry succeeds.
POST /api/documents-v2/drafts saves a draft; GET and PUT /api/documents-v2/drafts/{id} restore and update it. Send the current draftVersion when updating; a conflict returns 409. Saving does not issue a document or allocate a number. Bank/check dates, reference, bank, branch, account, check number, cashAmount and transactionTotal are retained as bounded top-level fields. DELETE archives the editable draft and POST /api/documents-v2/drafts/{id}/restore restores an eligible archived draft.
POST /api/documents-v2/create issues or continues the document. For a saved draft send sourceDraftId and the current draftVersion with the complete creation payload; the server retains its attempt snapshot. Preserve the same requestId and unchanged payload after timeout, unknown outcome, reload or continuation failure. Do not clear the stored attempt, pick another source, change provider or generate a fresh identity to bypass it. Only safeToEdit=true permits edited submission. The response requestId can be a diagnostic ID; keep the original client identity. A receipt needs an amount; invoice and invoice_receipt need detailed items. Manual payment fields and issuer permissions are revalidated by the server.
For POST /api/documents-v2/create, send complete finite numeric values. Row products, sums, VAT totals and balances must remain finite too. Invalid numbers return 400 DOCUMENT_NUMERIC_INPUT_INVALID with field and safeToEdit=true before customer, issuance-attempt, numbering or PDF writes. Explicit paid and VAT rates cannot be negative. Item allocation assessment uses quantity × price rather than supplied aggregate or row totals; the existing allocation thresholds and invoice-item rules remain unchanged.
POST /external/create-quote accepts up to 100 described items, or amount BEFORE VAT when items is absent or empty. Nonempty items override amount. Quantities must be positive; prices and discount must be non-negative, and discount cannot exceed the rounded subtotal. New quotes use quote_cents_v1: round unit prices and rows to cents, subtract discount, then round VAT once. Currency is ILS or USD. Invalid inputs return 400 QUOTE_ITEMS_INVALID, QUOTE_DISCOUNT_INVALID, QUOTE_INPUT_INVALID, DOCUMENT_NUMERIC_INPUT_INVALID, DOCUMENT_CURRENCY_UNSUPPORTED or DOCUMENT_PROVIDER_QUOTE_PAYMENT_SOURCE_FORBIDDEN with field and safeToEdit=true before customer, numbering or artifact writes. paymentId, parentDocumentId and refundEventId are not quote-creation inputs. The response includes currency, vatRate, subtotalBeforeVat (after discount), vatAmount, discount and the calculation version; conversion of a canonical quote preserves these exact cents. Existing accounting/refund arithmetic and issued originals are unchanged. Quote creation is not a signature or payment.
With an active verified CardCom binding, POST /external/create-quote creates a real provider Quote and preserves its immutable original PDF. Supply one stable requestId, Idempotency-Key or X-Idempotency-Key (1–180 ASCII letters, digits, underscores, dots, colons or hyphens); all supplied values must agree. Reuse the same body/key. Canonical quote_cents_v1 amounts and conversion remain unchanged. CardCom requires a positive final total; zero-price rows inside that total remain valid. An unsupported test binding, currency or separate-signature policy blocks dispatch. There is no internal fallback after provider dispatch.
DOCUMENT_PROVIDER_OUTCOME_UNKNOWN (409) and DOCUMENT_PROVIDER_LOCAL_PENDING (503) can mean a real record already exists. Retain operationId plus the original request identity/body. The owner can read GET /api/document-provider/operations/{operationId}, reconcile or complete the existing operation using Firebase Bearer authentication; these internal recovery routes do not accept X-API-Key. Do not create a fresh identity or another quote to bypass an unresolved outcome.
CardCom customer approval uses a separate linked acknowledgment. The original provider PDF, quote number and amounts stay unchanged. Capturing a signature can return 202 with signaturePending=true and preparing/failed publication; no downstream sales step or notification is authorized until the current original and acknowledgment PDF proofs are ready. GET /external/document/{id}/signature-status returns the current state, original pdfUrl and separate signatureAcknowledgmentPdfUrl. The acknowledgment is neither an invoice, receipt nor proof of payment. The owner opens it through POST /api/documents/{id}/access-link with artifactKind=signature_acknowledgment; default document opens the original. Access can be renewed without another issue or signature.
New PDF links use /d/{token} on RealPayment, without exposing a Storage address. Anyone possessing the link can view for 30 days; cancellation, revocation or a closed owner blocks access. Reopening/sharing can renew access without issuing a document again. If link preparation alone fails, success=true and pdfAvailable=true are preserved with pdfUrl=null and linkState=unavailable; do not repeat issuance. Previously shared Storage URLs retain their original expiry. Verified signed local PDFs are preserved; CardCom originals remain unchanged.
PUT /external/document/{id} uses X-API-Key. Customer/notes/metadata content of an emitted, signed, cancelled or signing/converting quote is protected with 409 QUOTE_DOCUMENT_EDIT_BLOCKED. Active protected quotes allow status=sent or viewed; changing them to draft/cancelled or reviving a cancelled quote returns 409 QUOTE_DOCUMENT_STATUS_CHANGE_BLOCKED. Use the supported cancellation flow. Genuine legacy quote drafts without issued artifacts, captured signatures or started operations remain editable for recognized fields. Owner and latest state are checked atomically; final accounting-document immutability remains enforced. This update does not replace the issued PDF or create an issuance/replay/provider capability.
Creation success, PDF availability, a paid source payment and notification delivery are separate results. Document QA for this release used controlled local data and responses; real issuance, financial operations, physical-device behavior and specialist legal/provider approval require their own evidence.
Ordinary external webhooks: V2 verification and original-event retries
Existing clients remain legacy until an explicit migration. X-RealPayment-Signature uses the public apiClientId as its HMAC key: it is weak compatibility data, not a dedicated-secret authenticity proof or a substitute for V2. Dedicated SaaS and server-managed authentication keep their own contracts.
After a dedicated owner/client key is installed in the API runtime and receiver backend, the active owner can enable dual_v2 using PUT /api/api-clients/{clientId}/webhook-signing at the site origin with a Firebase Bearer token. Send keyId, the current expectedVersion, and consumerReady=true. Inline secrets are rejected. configured and consumerConfirmedByOwner describe saved configuration and an owner attestation; neither proves a live receiver accepted V2. Missing key material returns 503 EXTERNAL_WEBHOOK_SIGNING_SECRET_UNAVAILABLE. New signing is not activated automatically.
V2 sends X-RealPayment-Signature-Version: 2, X-RealPayment-Key-Id, X-RealPayment-Timestamp (Unix seconds), X-RealPayment-Event-Id, X-Idempotency-Key and X-RealPayment-Signature-V2. The latter is sha256= plus HMAC-SHA256 of the exact UTF-8 string {attemptTimestamp}.{originalEventId}.{rawJsonBody}, using the client's dedicated private secret. The event header is X-RealPayment-Event. The legacy signature header remains alongside V2 during migration.
Verify the raw body before JSON parsing; do not reserialize it. Select Key-Id only from the receiver's installed client-specific key configuration, use a five-minute (300-second) clock window, require Event-Id and Idempotency-Key to match, and compare the HMAC in constant time. Atomically deduplicate by installed apiClientId and eventId with a body hash together with the business effect. A repeated matching event gets its saved acknowledgment; reject the same identity with changed content. HTTP 2xx proves endpoint acceptance only.
For payment.completed, the sender stores the original envelope before HTTP. An authorized administrator can use POST /api/admin/retry-webhook with webhookId to retry the same raw body, destination and event/idempotency IDs. Only the attempt timestamp/signature can change. Retrying delivery never charges, creates a document, reconciles a payment or writes the payment. Keep old key versions while their envelopes remain retryable. Historical failures without the original body return 409 EXTERNAL_WEBHOOK_ORIGINAL_BODY_UNAVAILABLE without sending; never reconstruct an event from today's payment or template.
POST /external/webhook/test uses X-API-Key and sends an actual payment.test HTTP message using the saved signing mode. A successful response proves endpoint acceptance, not a financial or business outcome. It does not create a charge or document and is separate from the completed-payment retry ledger. Legacy owner subscriptions for transaction.created/updated are a separate dispatcher and are not covered by this V2 contract.
Card refresh after a failed recurring payment
Use the existing refresh-card-link route with the owner's Firebase Bearer token internally or X-API-Key externally. Saving a replacement card requires the customer's approval and a verified provider result. It does not itself create a debit.
An unknown LowProfile/Create outcome keeps the original attempt and lock. The first response is 503 with paymentId and canRetry=false: RECURRING_CARD_REFRESH_PROVIDER_OUTCOME_UNKNOWN for ordinary plans, or SAAS_CARD_UPDATE_PROVIDER_OUTCOME_UNKNOWN for SaaS. A repeat receives 409 without another Create. A concurrent callback may already have changed the state; RECURRING_CARD_REFRESH_STATE_CHANGED also has canRetry=false. Retain the original identity and inspect it. No expiry-based unlock or blind retry is safe; without a returned LowProfileId, automated lookup is not established.
For an ordinary token plan, confirmed card replacement may allow the next due scheduler run to collect an overdue bill automatically. This existing timing is preserved. A dedicated SaaS plan waits for its explicit /external/recurring-payments/{id}/recover contract after a verified newer credential. Unknown charge outcomes must be reconciled before either flow; card replacement cannot bypass them.
A failure email to the owner is opt-in through notifyOwnerOnFailure; a visible failed payment does not prove an email was delivered. A recurring charge, its original document and actual email arrival each require their own evidence.
Opt-in token-first billing
Billing Enrollments v1 requires the persisted allowBillingEnrollments client policy. Both initial modes register a card without a browser debit. An immediate first payment is dispatched only after verified approval and the current agreement fence. A scheduled first payment uses the selected future date. The first debit never advances the independently selected next date.
Use a stable X-Idempotency-Key, immutable agreement identity and the returned revision. Cancel before marking an account free or replacing terms; pending_stop means a dispatched financial outcome is unresolved. A known failed payment can request one new token approval for that bill; an unknown outcome cannot be retried. Capabilities readiness is configuration evidence only. GET reconciles existing references and returns confirmed history/document URLs.
Loading API documentation
This page loads the RealPayment 0.13.7 OpenAPI specification.
הורדת קובץ OpenAPI