{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-docs/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["tabs","tab","admonition"]},"type":"markdown"},"seo":{"title":"Reefpay Docs","description":"Reefpay is the groundbreaking payment gateway that lets you integrate with the future of payments.","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"recipe-handle-payment-failures","__idx":0},"children":["Recipe: Handle payment failures"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"types-of-payment-failures","__idx":1},"children":["Types of payment failures"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Payment failures fall into three categories:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Category"},"children":["Category"]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Cause"},"children":["Cause"]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"response_status"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["response_status"]}]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Retryable?"},"children":["Retryable?"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Decline"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Issuer refused the transaction"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["declined"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Usually no — ask for a different card"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Error"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Processor or gateway issue"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Yes — retry with backoff"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Network failure"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Timeout, DNS, connection reset"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["(no response)"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Yes — retry with backoff"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"failure-decision-tree","__idx":2},"children":["Failure decision tree"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"img","attributes":{"src":"https://files.modern-mermaid.live/images/1776277334221-mermaid-diagram-1776277334330.png","alt":"image"},"children":[]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"retry-strategy","__idx":3},"children":["Retry strategy"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["exponential backoff with jitter"]}," to avoid overwhelming the API during outages."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"import time, random, requests, os\n\nAPI_KEY = os.environ[\"PARADISE_API_KEY\"]\nBASE = \"https://api.dev.paradisegateway.net\"\n\ndef send_transaction(payload, max_retries=3):\n    for attempt in range(max_retries):\n        try:\n            resp = requests.post(\n                f\"{BASE}/v1/transactions\",\n                headers={\n                    \"Content-Type\": \"application/json\",\n                    \"APIKEY\": API_KEY,\n                },\n                json=payload,\n                timeout=30,\n            )\n            result = resp.json()\n\n            if result.get(\"response_status\") == \"approved\":\n                return {\"success\": True, \"transaction\": result}\n\n            if result.get(\"response_status\") == \"declined\":\n                return {\n                    \"success\": False,\n                    \"retryable\": False,\n                    \"reason\": result.get(\"response_message\", \"Declined\"),\n                    \"correlation_id\": result.get(\"correlation_id\"),\n                }\n\n            if resp.status_code >= 400 and resp.status_code < 500:\n                return {\n                    \"success\": False,\n                    \"retryable\": False,\n                    \"reason\": f\"Client error: {resp.status_code}\",\n                    \"correlation_id\": result.get(\"correlation_id\"),\n                }\n\n        except requests.exceptions.Timeout:\n            pass  # will retry\n        except requests.exceptions.ConnectionError:\n            pass  # will retry\n\n        wait = (2 ** attempt) + random.uniform(0, 1)\n        print(f\"Attempt {attempt + 1} failed, retrying in {wait:.1f}s...\")\n        time.sleep(wait)\n\n    return {\"success\": False, \"retryable\": False, \"reason\": \"Max retries exceeded\"}\n","lang":"python"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"const API_KEY = process.env.PARADISE_API_KEY;\nconst BASE = \"https://api.dev.paradisegateway.net\";\n\nasync function sendTransaction(payload, maxRetries = 3) {\n  for (let attempt = 0; attempt < maxRetries; attempt++) {\n    try {\n      const controller = new AbortController();\n      const timer = setTimeout(() => controller.abort(), 30000);\n\n      const resp = await fetch(`${BASE}/v1/transactions`, {\n        method: \"POST\",\n        headers: { \"Content-Type\": \"application/json\", \"APIKEY\": API_KEY },\n        body: JSON.stringify(payload),\n        signal: controller.signal,\n      });\n      clearTimeout(timer);\n      const result = await resp.json();\n\n      if (result.response_status === \"approved\") {\n        return { success: true, transaction: result };\n      }\n\n      if (result.response_status === \"declined\") {\n        return {\n          success: false, retryable: false,\n          reason: result.response_message || \"Declined\",\n          correlationId: result.correlation_id,\n        };\n      }\n\n      if (resp.status >= 400 && resp.status < 500) {\n        return {\n          success: false, retryable: false,\n          reason: `Client error: ${resp.status}`,\n          correlationId: result.correlation_id,\n        };\n      }\n    } catch (err) {\n      // timeout or network error — will retry\n    }\n\n    const wait = 2 ** attempt * 1000 + Math.random() * 1000;\n    console.log(`Attempt ${attempt + 1} failed, retrying in ${(wait / 1000).toFixed(1)}s...`);\n    await new Promise((r) => setTimeout(r, wait));\n  }\n  return { success: false, retryable: false, reason: \"Max retries exceeded\" };\n}\n","lang":"javascript"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"logging-failures","__idx":4},"children":["Logging failures"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Log every failure with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["correlation_id"]}," so support can trace the request."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"import logging\n\nlogger = logging.getLogger(\"payments\")\n\ndef log_failure(result, payload):\n    logger.error(\n        \"Payment failed: reason=%s correlation_id=%s amount=%s type=%s\",\n        result.get(\"reason\"),\n        result.get(\"correlation_id\"),\n        payload.get(\"amount\"),\n        payload.get(\"type\"),\n    )\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-to-show-the-customer","__idx":5},"children":["What to show the customer"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Failure type"},"children":["Failure type"]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"User-facing message"},"children":["User-facing message"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Decline"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["\"Your payment was declined. Please try a different payment method.\""]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Temporary error"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["\"We're having trouble processing your payment. Please try again.\""]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Timeout (all retries exhausted)"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["\"We couldn't reach the payment processor. Please try again later.\""]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Validation error (4xx)"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["\"There's an issue with your payment details. Please check and retry.\""]}]}]}]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"Security"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Never expose ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["response_code"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["response_message"]},", processor details, or stack traces to the customer. Log them server-side and show generic, friendly messages."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"failure-summary-table","__idx":6},"children":["Failure summary table"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"HTTP status"},"children":["HTTP status"]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"response_status"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["response_status"]}]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Action"},"children":["Action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["200"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["approved"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Fulfill order"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["200"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["declined"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Ask for different payment method"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["200"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Retry with backoff"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["400"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["—"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Fix the request (missing/invalid fields)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["401"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["—"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Check API key"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["404"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["—"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Check the endpoint or resource ID"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["422"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["—"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Validation failed (for example, invalid card number)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["5xx"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["—"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Retry with backoff"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["(no response)"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["—"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Retry with backoff"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"next-steps","__idx":7},"children":["Next steps"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/payment-cookbook/handle-declined-transactions"},"children":["Handle declined transactions"]}," — detailed decline handling"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/tutorials/payment-cookbook/auth-returns"},"children":["ACH returns"]}," — ACH-specific failure patterns"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/concepts/api-fundamentals/error-handling"},"children":["Error handling concepts"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/get-started/integration-best-practices"},"children":["Integration best practices"]}]}]}]},"headings":[{"value":"Recipe: Handle payment failures","id":"recipe-handle-payment-failures","depth":1},{"value":"Types of payment failures","id":"types-of-payment-failures","depth":2},{"value":"Failure decision tree","id":"failure-decision-tree","depth":2},{"value":"Retry strategy","id":"retry-strategy","depth":2},{"value":"Logging failures","id":"logging-failures","depth":2},{"value":"What to show the customer","id":"what-to-show-the-customer","depth":2},{"value":"Failure summary table","id":"failure-summary-table","depth":2},{"value":"Next steps","id":"next-steps","depth":2}],"frontmatter":{"title":"Recipe: Handle payment failures","shortTitle":"Handle payment failures","intro":"Build resilient payment flows that gracefully handle network errors, timeouts, processor outages, and unexpected API responses.","type":"tutorial","seo":{"title":""}},"lastModified":"2026-06-05T02:46:44.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/tutorials/payment-cookbook/handle-payment-failures","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}