{
  "info": {
    "name": "FAYGAW — API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": "FAYGAW API : Checkout, Direct-Link Checkout, Payout et Balance. Les créations Direct-Link et Payout sont séparées pour Wave et Orange Money. Modifiez les valeurs d’exemple directement dans les requêtes. Pour une nouvelle opération, changez la référence et la clé Idempotency-Key. Après un timeout, conservez exactement la même clé et le même corps. Pour lire une opération, remplacez l’identifiant d’exemple par celui reçu à la création. Vérifiez toujours les montants et les bénéficiaires avant l’envoi.\n\nLes limites SANDBOX s’appliquent indépendamment par provider et par partenaire. Par défaut, le minimum Checkout est de 10 XOF et le minimum Payout de 100 XOF. Les minimums et plafonds SANDBOX peuvent être adaptés sur demande du partenaire auprès de Faygaw, après validation. Respectez les limites indiquées dans la réponse d’erreur et contactez Faygaw si une adaptation est nécessaire.\n\nSANDBOX limits apply independently per provider and partner. The default minimum is 10 XOF for Checkout and 100 XOF for Payout. SANDBOX minimums and limits can be adjusted upon the partner’s request to Faygaw, subject to approval. Follow the limits reported in the error response and contact Faygaw if an adjustment is needed.\n\nRefund : prévu / planned, non activé / not enabled.\n\nLes reprises automatiques durent au maximum 72 heures après la demande initiale. Un refus de tentative ne rend pas le paiement définitivement non remboursable. Après cette limite, relancez le même Refund avec POST /v1/refunds/{refund_id}/retry et une nouvelle Idempotency-Key : une seule tentative, sans nouveau cycle automatique de 72 heures. Réutilisez la même clé et le même corps après une réponse perdue. HTTP 202 confirme la prise en charge, pas le remboursement ; consultez GET. Un Refund déjà SUCCEEDED ne déclenche aucun nouvel envoi. Aucun nouveau frais FAYGAW ; restitution des montants confirmée seulement par SUCCEEDED. Les montants indiqués ne sont restitués que si status=SUCCEEDED.\nAutomatic retries run for at most 72 hours from the original request. A refused attempt does not make the payment permanently non-refundable. After that limit, retry the same Refund with POST /v1/refunds/{refund_id}/retry and a new Idempotency-Key: one attempt, without opening another automatic 72-hour cycle. Reuse the same key and body after a lost response. HTTP 202 acknowledges acceptance, not completion; use GET. An already SUCCEEDED Refund triggers no new provider send. No new FAYGAW fee; amounts are confirmed returned only at SUCCEEDED. Amounts are returned only when status=SUCCEEDED."
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.faygaw.org/v1"
    },
    {
      "key": "api_key",
      "value": "",
      "description": "Clé API à renseigner localement ; ne pas la partager dans un export."
    },
    {
      "key": "expected_environment",
      "value": "SANDBOX",
      "description": "Contrôle de la réponse uniquement ; l’environnement est déterminé par la clé API."
    },
    {
      "key": "payout_phone_number",
      "value": "",
      "description": "Véritable destinataire, au format international sans +, à renseigner avant envoi."
    }
  ],
  "item": [
    {
      "name": "Checkout",
      "item": [
        {
          "name": "Créer une session Checkout — checkout:write",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/checkouts",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "example-checkout-abc123XYZ"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": \"100\",\n  \"currency\": \"XOF\",\n  \"client_reference\": \"checkout_abc123XYZ\",\n  \"description\": \"Commande test\",\n  \"success_url\": \"https://merchant.example/payment/success\",\n  \"error_url\": \"https://merchant.example/payment/error\",\n  \"metadata\": {\n    \"merchant_site_url\": \"https://merchant.example/checkout/checkout_abc123XYZ\",\n    \"language\": \"fr\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Créez et consultez un Checkout hébergé. Confirmez le paiement avec GET ou checkout.paid signé, jamais par un retour navigateur. Modifiez les valeurs d’exemple directement dans les requêtes. Pour une nouvelle opération, changez la référence et la clé Idempotency-Key. Après un timeout, conservez exactement la même clé et le même corps. Pour lire une opération, remplacez l’identifiant d’exemple par celui reçu à la création. Vérifiez toujours les montants et les bénéficiaires avant l’envoi."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const data=pm.response.json();",
                  "pm.test('Expected successful response',()=>pm.expect(pm.response.code).to.eql(pm.request.method==='POST'?201:200));",
                  "pm.test('Private response is not cached',()=>pm.expect(pm.response.headers.get('Cache-Control')).to.eql('no-store'));",
                  "pm.test('Owned Checkout in expected environment',()=>{",
                  "  pm.expect(data.object).to.eql('checkout');",
                  "  pm.expect(data.id).to.match(/^co_[a-f0-9]{32}$/);",
                  "  pm.expect(data.environment).to.eql(pm.variables.get('expected_environment'));",
                  "  pm.expect(data.currency).to.eql('XOF');",
                  "  pm.expect(data.amount).to.match(/^[0-9]+$/);",
                  "  pm.expect(['OPEN','PROCESSING','UNKNOWN','SUCCEEDED','FAILED','EXPIRED','CANCELLED']).to.include(data.status);",
                  "  if(pm.request.method==='GET'){pm.expect(data.id).to.eql(pm.variables.replaceIn(pm.request.url.toString()).split('?')[0].split('/').pop());}",
                  "});",
                  "pm.test('Fee is absent before selection or an exact frozen whole-XOF quote',()=>{",
                  "  if(data.provider===null){pm.expect(data.faygaw_partner_fee).to.eql(null);pm.expect(data.net_amount).to.eql(null);}",
                  "  else{",
                  "    pm.expect(['WAVE','ORANGE_MONEY']).to.include(data.provider);",
                  "    pm.expect(data.faygaw_partner_fee).to.match(/^[0-9]+$/);pm.expect(data.net_amount).to.match(/^[0-9]+$/);",
                  "    ",
                  "  }",
                  "});",
                  "pm.test('Hosted capability stays on the expected origin',()=>{",
                  "  if(data.checkout_link!==undefined){",
                  "    pm.expect(data.checkout_link).to.match(/^https:\\/\\/hosted-checkout\\.faygaw\\.org\\/c\\/co_[a-f0-9]{32}#token=hcs_(sb|pr)_[A-Za-z0-9_-]{43}$/);",
                  "    pm.expect(data.checkout_link.split('#token=')[0]).to.eql('https://hosted-checkout.faygaw.org/c/'+data.id);",
                  "    pm.expect(data.checkout_link.split('#token=')[1].slice(0,7)).to.eql(data.environment==='SANDBOX'?'hcs_sb_':'hcs_pr_');",
                  "  }",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Lire le Checkout — checkout:read",
          "request": {
            "method": "GET",
            "url": "{{base_url}}/checkouts/co_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              }
            ],
            "description": "Créez et consultez un Checkout hébergé. Confirmez le paiement avec GET ou checkout.paid signé, jamais par un retour navigateur. Modifiez les valeurs d’exemple directement dans les requêtes. Pour une nouvelle opération, changez la référence et la clé Idempotency-Key. Après un timeout, conservez exactement la même clé et le même corps. Pour lire une opération, remplacez l’identifiant d’exemple par celui reçu à la création. Vérifiez toujours les montants et les bénéficiaires avant l’envoi."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const data=pm.response.json();",
                  "pm.test('Expected successful response',()=>pm.expect(pm.response.code).to.eql(pm.request.method==='POST'?201:200));",
                  "pm.test('Private response is not cached',()=>pm.expect(pm.response.headers.get('Cache-Control')).to.eql('no-store'));",
                  "pm.test('Owned Checkout in expected environment',()=>{",
                  "  pm.expect(data.object).to.eql('checkout');",
                  "  pm.expect(data.id).to.match(/^co_[a-f0-9]{32}$/);",
                  "  pm.expect(data.environment).to.eql(pm.variables.get('expected_environment'));",
                  "  pm.expect(data.currency).to.eql('XOF');",
                  "  pm.expect(data.amount).to.match(/^[0-9]+$/);",
                  "  pm.expect(['OPEN','PROCESSING','UNKNOWN','SUCCEEDED','FAILED','EXPIRED','CANCELLED']).to.include(data.status);",
                  "  if(pm.request.method==='GET'){pm.expect(data.id).to.eql(pm.variables.replaceIn(pm.request.url.toString()).split('?')[0].split('/').pop());}",
                  "});",
                  "pm.test('Fee is absent before selection or an exact frozen whole-XOF quote',()=>{",
                  "  if(data.provider===null){pm.expect(data.faygaw_partner_fee).to.eql(null);pm.expect(data.net_amount).to.eql(null);}",
                  "  else{",
                  "    pm.expect(['WAVE','ORANGE_MONEY']).to.include(data.provider);",
                  "    pm.expect(data.faygaw_partner_fee).to.match(/^[0-9]+$/);pm.expect(data.net_amount).to.match(/^[0-9]+$/);",
                  "    ",
                  "  }",
                  "});",
                  "pm.test('Hosted capability stays on the expected origin',()=>{",
                  "  if(data.checkout_link!==undefined){",
                  "    pm.expect(data.checkout_link).to.match(/^https:\\/\\/hosted-checkout\\.faygaw\\.org\\/c\\/co_[a-f0-9]{32}#token=hcs_(sb|pr)_[A-Za-z0-9_-]{43}$/);",
                  "    pm.expect(data.checkout_link.split('#token=')[0]).to.eql('https://hosted-checkout.faygaw.org/c/'+data.id);",
                  "    pm.expect(data.checkout_link.split('#token=')[1].slice(0,7)).to.eql(data.environment==='SANDBOX'?'hcs_sb_':'hcs_pr_');",
                  "  }",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Balance",
      "item": [
        {
          "name": "Consulter le solde — balance:read",
          "request": {
            "method": "GET",
            "url": "{{base_url}}/balances",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "description": "## Champs de réponse / Response fields\n\n**environment** — Environnement déterminé par la clé API.\n\nEnvironment determined by the API key.\n\n**state** — RECORDED : des comptes sont disponibles. NOT_INITIALIZED : aucun compte initialisé ; accounts est vide.\n\nRECORDED: accounts are available. NOT_INITIALIZED: no account is initialized; accounts is empty.\n\n**accounts** — Comptes du Partner, par type, provider et devise.\n\nPartner accounts, by type, provider and currency.\n\n**observed_at** — Date et heure UTC de la consultation.\n\nUTC date and time of this read.\n\n**source** — Origine des données de solde.\n\nSource of the balance data.\n\n**reservation_consistency** — Indicateur de cohérence : MATCH ou NOT_APPLICABLE en l’absence de compte.\n\nConsistency indicator: MATCH, or NOT_APPLICABLE when there are no accounts.\n\n**account_id** — Identifiant du compte.\n\nAccount identifier.\n\n**account_type** — Type du compte : PROVIDER ou FAYGAW.\n\nAccount type: PROVIDER or FAYGAW.\n\n**provider** — Provider associé au compte, ou null lorsqu’aucun provider n’est associé.\n\nAssociated provider, or null when no provider is associated.\n\n**provider.code** — Code du provider, par exemple WAVE ou ORANGE_MONEY.\n\nProvider code, such as WAVE or ORANGE_MONEY.\n\n**provider.name** — Nom d’affichage du provider.\n\nProvider display name.\n\n**status** — État du compte : ACTIVE, SUSPENDED ou CLOSED.\n\nAccount status: ACTIVE, SUSPENDED or CLOSED.\n\n**currency** — Code de devise ISO, par exemple XOF.\n\nISO currency code, such as XOF.\n\n**minor_unit** — Nombre de décimales de la devise. Pour XOF : 0 ; une unité minimale représente un franc.\n\nCurrency decimal places. For XOF: 0; one minor unit is one franc.\n\n**current_minor** — Solde courant en unités minimales, sous forme de chaîne entière. Ce montant inclut reserved_minor.\n\nCurrent balance in minor units, as an integer string. It includes reserved_minor.\n\n**reserved_minor** — Part du solde temporairement indisponible pour d’autres opérations, déjà incluse dans current_minor.\n\nBalance portion temporarily unavailable for other operations, already included in current_minor.\n\n**version** — Version du compte retourné, sous forme de chaîne entière.\n\nVersion of the returned account, as an integer string.\n\n**updated_at** — Date et heure UTC de dernière mise à jour du compte.\n\nUTC date and time of the latest account update."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Balance contract\", function () {",
                  "  pm.response.to.have.status(200);",
                  "  pm.expect(pm.response.headers.get(\"Cache-Control\")).to.eql(\"no-store\");",
                  "  const b = pm.response.json();",
                  "  pm.expect(b.environment).to.eql(pm.variables.get(\"expected_environment\"));",
                  "  pm.expect(b.source).to.eql(\"PARTNER_ACCOUNT_PROJECTION\");",
                  "  pm.expect(b.accounts).to.be.an(\"array\");",
                  "  pm.expect(b.state).to.eql(b.accounts.length ? \"RECORDED\" : \"NOT_INITIALIZED\");",
                  "  pm.expect(b.reservation_consistency).to.eql(b.accounts.length ? \"MATCH\" : \"NOT_APPLICABLE\");",
                  "  pm.expect(b.observed_at).to.be.a(\"string\");",
                  "  b.accounts.forEach(function (a) {",
                  "    [\"current_minor\", \"reserved_minor\", \"version\"].forEach(function (k) {",
                  "      pm.expect(a[k]).to.be.a(\"string\").and.match(/^-?[0-9]+$/);",
                  "    });",
                  "    if(a.provider !== null){pm.expect(a.provider.code).to.be.a(\"string\");pm.expect(a.provider.name).to.be.a(\"string\");}",
                  "    if(a.account_type === \"FAYGAW\")pm.expect(a.provider).to.eql(null);",
                  "    pm.expect(a.currency).to.match(/^[A-Z]{3}$/);",
                  "    pm.expect(a.minor_unit).to.be.within(0, 9);",
                  "    pm.expect(a).not.to.have.property(\"available_minor\");",
                  "  });",
                  "});"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "Comptes avec providers — exemple fictif",
              "originalRequest": {
                "method": "GET",
                "url": "{{base_url}}/balances",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "description": "## Champs de réponse / Response fields\n\n**environment** — Environnement déterminé par la clé API.\n\nEnvironment determined by the API key.\n\n**state** — RECORDED : des comptes sont disponibles. NOT_INITIALIZED : aucun compte initialisé ; accounts est vide.\n\nRECORDED: accounts are available. NOT_INITIALIZED: no account is initialized; accounts is empty.\n\n**accounts** — Comptes du Partner, par type, provider et devise.\n\nPartner accounts, by type, provider and currency.\n\n**observed_at** — Date et heure UTC de la consultation.\n\nUTC date and time of this read.\n\n**source** — Origine des données de solde.\n\nSource of the balance data.\n\n**reservation_consistency** — Indicateur de cohérence : MATCH ou NOT_APPLICABLE en l’absence de compte.\n\nConsistency indicator: MATCH, or NOT_APPLICABLE when there are no accounts.\n\n**account_id** — Identifiant du compte.\n\nAccount identifier.\n\n**account_type** — Type du compte : PROVIDER ou FAYGAW.\n\nAccount type: PROVIDER or FAYGAW.\n\n**provider** — Provider associé au compte, ou null lorsqu’aucun provider n’est associé.\n\nAssociated provider, or null when no provider is associated.\n\n**provider.code** — Code du provider, par exemple WAVE ou ORANGE_MONEY.\n\nProvider code, such as WAVE or ORANGE_MONEY.\n\n**provider.name** — Nom d’affichage du provider.\n\nProvider display name.\n\n**status** — État du compte : ACTIVE, SUSPENDED ou CLOSED.\n\nAccount status: ACTIVE, SUSPENDED or CLOSED.\n\n**currency** — Code de devise ISO, par exemple XOF.\n\nISO currency code, such as XOF.\n\n**minor_unit** — Nombre de décimales de la devise. Pour XOF : 0 ; une unité minimale représente un franc.\n\nCurrency decimal places. For XOF: 0; one minor unit is one franc.\n\n**current_minor** — Solde courant en unités minimales, sous forme de chaîne entière. Ce montant inclut reserved_minor.\n\nCurrent balance in minor units, as an integer string. It includes reserved_minor.\n\n**reserved_minor** — Part du solde temporairement indisponible pour d’autres opérations, déjà incluse dans current_minor.\n\nBalance portion temporarily unavailable for other operations, already included in current_minor.\n\n**version** — Version du compte retourné, sous forme de chaîne entière.\n\nVersion of the returned account, as an integer string.\n\n**updated_at** — Date et heure UTC de dernière mise à jour du compte.\n\nUTC date and time of the latest account update."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "Cache-Control",
                  "value": "no-store"
                }
              ],
              "body": "{\n  \"environment\": \"SANDBOX\",\n  \"state\": \"RECORDED\",\n  \"accounts\": [\n    {\n      \"account_id\": \"pac_11111111111111111111111111111111\",\n      \"account_type\": \"PROVIDER\",\n      \"provider\": {\n        \"code\": \"WAVE\",\n        \"name\": \"Wave\"\n      },\n      \"status\": \"ACTIVE\",\n      \"currency\": \"XOF\",\n      \"minor_unit\": 0,\n      \"current_minor\": \"10000\",\n      \"reserved_minor\": \"1500\",\n      \"version\": \"1\",\n      \"updated_at\": \"2026-10-26T12:00:00.000000Z\"\n    },\n    {\n      \"account_id\": \"pac_22222222222222222222222222222222\",\n      \"account_type\": \"PROVIDER\",\n      \"provider\": {\n        \"code\": \"ORANGE_MONEY\",\n        \"name\": \"Orange Money\"\n      },\n      \"status\": \"ACTIVE\",\n      \"currency\": \"XOF\",\n      \"minor_unit\": 0,\n      \"current_minor\": \"2500\",\n      \"reserved_minor\": \"0\",\n      \"version\": \"2\",\n      \"updated_at\": \"2026-10-26T12:00:00.000000Z\"\n    },\n    {\n      \"account_id\": \"pac_33333333333333333333333333333333\",\n      \"account_type\": \"PROVIDER\",\n      \"provider\": {\n        \"code\": \"YAS\",\n        \"name\": \"Yas\"\n      },\n      \"status\": \"ACTIVE\",\n      \"currency\": \"XOF\",\n      \"minor_unit\": 0,\n      \"current_minor\": \"0\",\n      \"reserved_minor\": \"0\",\n      \"version\": \"3\",\n      \"updated_at\": \"2026-10-26T12:00:00.000000Z\"\n    }\n  ],\n  \"observed_at\": \"2026-10-26T12:01:00.000000Z\",\n  \"source\": \"PARTNER_ACCOUNT_PROJECTION\",\n  \"reservation_consistency\": \"MATCH\"\n}"
            }
          ]
        },
        {
          "name": "Sans authentification — 401",
          "request": {
            "method": "GET",
            "url": "{{base_url}}/balances",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "auth": {
              "type": "noauth"
            },
            "description": "## Champs de réponse / Response fields\n\n**environment** — Environnement déterminé par la clé API.\n\nEnvironment determined by the API key.\n\n**state** — RECORDED : des comptes sont disponibles. NOT_INITIALIZED : aucun compte initialisé ; accounts est vide.\n\nRECORDED: accounts are available. NOT_INITIALIZED: no account is initialized; accounts is empty.\n\n**accounts** — Comptes du Partner, par type, provider et devise.\n\nPartner accounts, by type, provider and currency.\n\n**observed_at** — Date et heure UTC de la consultation.\n\nUTC date and time of this read.\n\n**source** — Origine des données de solde.\n\nSource of the balance data.\n\n**reservation_consistency** — Indicateur de cohérence : MATCH ou NOT_APPLICABLE en l’absence de compte.\n\nConsistency indicator: MATCH, or NOT_APPLICABLE when there are no accounts.\n\n**account_id** — Identifiant du compte.\n\nAccount identifier.\n\n**account_type** — Type du compte : PROVIDER ou FAYGAW.\n\nAccount type: PROVIDER or FAYGAW.\n\n**provider** — Provider associé au compte, ou null lorsqu’aucun provider n’est associé.\n\nAssociated provider, or null when no provider is associated.\n\n**provider.code** — Code du provider, par exemple WAVE ou ORANGE_MONEY.\n\nProvider code, such as WAVE or ORANGE_MONEY.\n\n**provider.name** — Nom d’affichage du provider.\n\nProvider display name.\n\n**status** — État du compte : ACTIVE, SUSPENDED ou CLOSED.\n\nAccount status: ACTIVE, SUSPENDED or CLOSED.\n\n**currency** — Code de devise ISO, par exemple XOF.\n\nISO currency code, such as XOF.\n\n**minor_unit** — Nombre de décimales de la devise. Pour XOF : 0 ; une unité minimale représente un franc.\n\nCurrency decimal places. For XOF: 0; one minor unit is one franc.\n\n**current_minor** — Solde courant en unités minimales, sous forme de chaîne entière. Ce montant inclut reserved_minor.\n\nCurrent balance in minor units, as an integer string. It includes reserved_minor.\n\n**reserved_minor** — Part du solde temporairement indisponible pour d’autres opérations, déjà incluse dans current_minor.\n\nBalance portion temporarily unavailable for other operations, already included in current_minor.\n\n**version** — Version du compte retourné, sous forme de chaîne entière.\n\nVersion of the returned account, as an integer string.\n\n**updated_at** — Date et heure UTC de dernière mise à jour du compte.\n\nUTC date and time of the latest account update."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Missing key\", () => { pm.response.to.have.status(401); pm.expect(pm.response.headers.get(\"Cache-Control\")).to.eql(\"no-store\"); });"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Direct-Link Checkout",
      "item": [
        {
          "name": "Créer un Direct-Link Wave — checkout:write",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/dl-checkouts",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "example-dl-wave-abc123XYZ"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": \"100\",\n  \"currency\": \"XOF\",\n  \"client_reference\": \"dl_wave_abc123XYZ\",\n  \"description\": \"Test Direct-Link Wave\",\n  \"success_url\": \"https://merchant.example/success\",\n  \"error_url\": \"https://merchant.example/error\",\n  \"metadata\": {\n    \"language\": \"fr\"\n  },\n  \"payment_method\": {\n    \"provider\": \"WAVE\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Créez un Direct-Link Wave ou Orange Money et utilisez ses launch_options. Confirmez le paiement avec GET ou checkout.paid signé. Modifiez les valeurs d’exemple directement dans les requêtes. Pour une nouvelle opération, changez la référence et la clé Idempotency-Key. Après un timeout, conservez exactement la même clé et le même corps. Pour lire une opération, remplacez l’identifiant d’exemple par celui reçu à la création. Vérifiez toujours les montants et les bénéficiaires avant l’envoi."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const body=pm.response.json();",
                  "pm.test('Known response',()=>pm.expect([201,400,401,403,409,422,429,503]).to.include(pm.response.code));",
                  "if(pm.response.code===201){",
                  " pm.test('Requested provider',()=>pm.expect(body.provider).to.eql(JSON.parse(pm.request.body.raw).payment_method.provider));",
                  " pm.test('No Hosted capability',()=>pm.expect(body.checkout_link).to.eql(undefined));",
                  " pm.test('Provider application identities',()=>{if(body.status==='PROCESSING'){pm.expect(body.launch_options.map(x=>x.app)).to.eql(body.provider==='WAVE'?['WAVE']:['ORANGE_MONEY','MAXIT']);}});",
                  "}else if(body.checkout){pm.test('No uncertain payable launch',()=>pm.expect(body.checkout.launch_options).to.eql([]));}"
                ]
              }
            }
          ]
        },
        {
          "name": "Créer un Direct-Link OM — checkout:write",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/dl-checkouts",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "example-dl-om-abc123XYZ"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": \"100\",\n  \"currency\": \"XOF\",\n  \"client_reference\": \"dl_om_abc123XYZ\",\n  \"description\": \"Test Direct-Link OM\",\n  \"success_url\": \"https://merchant.example/success\",\n  \"error_url\": \"https://merchant.example/error\",\n  \"metadata\": {\n    \"language\": \"fr\"\n  },\n  \"payment_method\": {\n    \"provider\": \"ORANGE_MONEY\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Créez un Direct-Link Wave ou Orange Money et utilisez ses launch_options. Confirmez le paiement avec GET ou checkout.paid signé. Modifiez les valeurs d’exemple directement dans les requêtes. Pour une nouvelle opération, changez la référence et la clé Idempotency-Key. Après un timeout, conservez exactement la même clé et le même corps. Pour lire une opération, remplacez l’identifiant d’exemple par celui reçu à la création. Vérifiez toujours les montants et les bénéficiaires avant l’envoi."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const body=pm.response.json();",
                  "pm.test('Known response',()=>pm.expect([201,400,401,403,409,422,429,503]).to.include(pm.response.code));",
                  "if(pm.response.code===201){",
                  " pm.test('Requested provider',()=>pm.expect(body.provider).to.eql(JSON.parse(pm.request.body.raw).payment_method.provider));",
                  " pm.test('No Hosted capability',()=>pm.expect(body.checkout_link).to.eql(undefined));",
                  " pm.test('Provider application identities',()=>{if(body.status==='PROCESSING'){pm.expect(body.launch_options.map(x=>x.app)).to.eql(body.provider==='WAVE'?['WAVE']:['ORANGE_MONEY','MAXIT']);}});",
                  "}else if(body.checkout){pm.test('No uncertain payable launch',()=>pm.expect(body.checkout.launch_options).to.eql([]));}"
                ]
              }
            }
          ]
        },
        {
          "name": "Lire le Checkout — checkout:read",
          "request": {
            "method": "GET",
            "url": "{{base_url}}/checkouts/co_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              }
            ],
            "description": "Créez un Direct-Link Wave ou Orange Money et utilisez ses launch_options. Confirmez le paiement avec GET ou checkout.paid signé. Modifiez les valeurs d’exemple directement dans les requêtes. Pour une nouvelle opération, changez la référence et la clé Idempotency-Key. Après un timeout, conservez exactement la même clé et le même corps. Pour lire une opération, remplacez l’identifiant d’exemple par celui reçu à la création. Vérifiez toujours les montants et les bénéficiaires avant l’envoi."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const data=pm.response.json();",
                  "pm.test('Expected successful response',()=>pm.expect(pm.response.code).to.eql(pm.request.method==='POST'?201:200));",
                  "pm.test('Private response is not cached',()=>pm.expect(pm.response.headers.get('Cache-Control')).to.eql('no-store'));",
                  "pm.test('Owned Checkout in expected environment',()=>{",
                  "  pm.expect(data.object).to.eql('checkout');",
                  "  pm.expect(data.id).to.match(/^co_[a-f0-9]{32}$/);",
                  "  pm.expect(data.environment).to.eql(pm.variables.get('expected_environment'));",
                  "  pm.expect(data.currency).to.eql('XOF');",
                  "  pm.expect(data.amount).to.match(/^[0-9]+$/);",
                  "  pm.expect(['OPEN','PROCESSING','UNKNOWN','SUCCEEDED','FAILED','EXPIRED','CANCELLED']).to.include(data.status);",
                  "  if(pm.request.method==='GET'){pm.expect(data.id).to.eql(pm.variables.replaceIn(pm.request.url.toString()).split('?')[0].split('/').pop());}",
                  "});",
                  "pm.test('Fee is absent before selection or an exact frozen whole-XOF quote',()=>{",
                  "  if(data.provider===null){pm.expect(data.faygaw_partner_fee).to.eql(null);pm.expect(data.net_amount).to.eql(null);}",
                  "  else{",
                  "    pm.expect(['WAVE','ORANGE_MONEY']).to.include(data.provider);",
                  "    pm.expect(data.faygaw_partner_fee).to.match(/^[0-9]+$/);pm.expect(data.net_amount).to.match(/^[0-9]+$/);",
                  "    ",
                  "  }",
                  "});",
                  "pm.test('Hosted capability stays on the expected origin',()=>{",
                  "  if(data.checkout_link!==undefined){",
                  "    pm.expect(data.checkout_link).to.match(/^https:\\/\\/hosted-checkout\\.faygaw\\.org\\/c\\/co_[a-f0-9]{32}#token=hcs_(sb|pr)_[A-Za-z0-9_-]{43}$/);",
                  "    pm.expect(data.checkout_link.split('#token=')[0]).to.eql('https://hosted-checkout.faygaw.org/c/'+data.id);",
                  "    pm.expect(data.checkout_link.split('#token=')[1].slice(0,7)).to.eql(data.environment==='SANDBOX'?'hcs_sb_':'hcs_pr_');",
                  "  }",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Payout",
      "item": [
        {
          "name": "Créer un Payout Wave — payout:write",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/payouts",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "example-payout-wave-abc123XYZ"
              }
            ],
            "description": "Le Payout est disponible avec Wave et Orange Money au Sénégal, en XOF. amount correspond au montant à envoyer au bénéficiaire. Idempotency-Key est obligatoire et client_reference doit être unique. Utilisez un numéro international sans +, par exemple 221771234567. Pour Orange Money : provider: ORANGE_MONEY. HTTP 201 CREATED avec status PROCESSING confirme la création ; le résultat final est asynchrone. Consultez GET /payouts/{payout_id} ou écoutez payout.succeeded et payout.failed. Un rejeu idempotent conserve la réponse initiale. UNKNOWN signifie que le résultat final du payout n’est pas encore déterminé. Ne soumettez pas une opération de remplacement. Continuez à récupérer le payout existant jusqu’à obtention d’un statut terminal. Modifiez les valeurs d’exemple directement dans les requêtes. Pour une nouvelle opération, changez la référence et la clé Idempotency-Key. Après un timeout, conservez exactement la même clé et le même corps. Pour lire une opération, remplacez l’identifiant d’exemple par celui reçu à la création. Vérifiez toujours les montants et les bénéficiaires avant l’envoi.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": \"100\",\n  \"currency\": \"XOF\",\n  \"provider\": \"WAVE\",\n  \"recipient\": {\n    \"phone_number\": \"{{payout_phone_number}}\"\n  },\n  \"client_reference\": \"abc123XYZ-WAVE\",\n  \"reason\": \"Test Payout Wave\",\n  \"metadata\": {\n    \"source\": \"postman\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const data=pm.response.json();",
                  "pm.test('Known HTTP response',()=>pm.expect(pm.request.method==='POST'?[201,400,401,403,409,422,429,503]:[200,400,401,403,404,429,503]).to.include(pm.response.code));",
                  "if(pm.response.code===201||pm.response.code===200){",
                  " pm.test('Payout response contract',()=>{",
                  "  pm.expect(data.object).to.eql('payout');pm.expect(data.environment).to.eql(pm.variables.get('expected_environment'));",
                  "  pm.expect(['WAVE','ORANGE_MONEY']).to.include(data.provider);pm.expect(data.currency).to.eql('XOF');pm.expect(typeof data.livemode).to.eql('boolean');",
                  "  pm.expect(data.id).to.match(/^po_[a-f0-9]{32}$/);pm.expect(data.transaction_id).to.match(/^txn_[a-f0-9]{32}$/);",
                  "  pm.expect(['PENDING','PROCESSING','UNKNOWN','SUCCEEDED','FAILED']).to.include(data.status);",
                  "  for(const key of ['amount','faygaw_partner_fee','total_amount']){pm.expect(typeof data[key]).to.eql('string');pm.expect(data[key]).to.match(/^(0|[1-9][0-9]*)$/);}",
                  "  pm.expect(BigInt(data.amount)>0n).to.eql(true);",
                  "  if(pm.request.method==='POST'){const sent=JSON.parse(pm.variables.replaceIn(pm.request.body.raw));pm.expect(pm.response.code).to.eql(201);pm.expect(data.amount).to.eql(sent.amount);pm.expect(data.client_reference).to.eql(sent.client_reference);pm.expect(data.provider).to.eql(sent.provider);}",
                  "  else{pm.expect(pm.response.code).to.eql(200);pm.expect(data.id).to.eql(pm.variables.replaceIn(pm.request.url.toString()).split('?')[0].split('/').pop());}",
                  "  if(data.recipient!==undefined)pm.expect(data.recipient.phone_number).to.match(/^221[1-9][0-9]{8}$/);",
                  " });",
                  "}else{pm.test('Structured API error',()=>{pm.expect(typeof data.error.code).to.eql('string');pm.expect(typeof data.error.request_id).to.eql('string');});}"
                ]
              }
            }
          ]
        },
        {
          "name": "Créer un Payout OM — payout:write",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/payouts",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "example-payout-om-abc123XYZ"
              }
            ],
            "description": "Le Payout est disponible avec Wave et Orange Money au Sénégal, en XOF. amount correspond au montant à envoyer au bénéficiaire. Idempotency-Key est obligatoire et client_reference doit être unique. Utilisez un numéro international sans +, par exemple 221771234567. Pour Orange Money : provider: ORANGE_MONEY. HTTP 201 CREATED avec status PROCESSING confirme la création ; le résultat final est asynchrone. Consultez GET /payouts/{payout_id} ou écoutez payout.succeeded et payout.failed. Un rejeu idempotent conserve la réponse initiale. UNKNOWN signifie que le résultat final du payout n’est pas encore déterminé. Ne soumettez pas une opération de remplacement. Continuez à récupérer le payout existant jusqu’à obtention d’un statut terminal. Modifiez les valeurs d’exemple directement dans les requêtes. Pour une nouvelle opération, changez la référence et la clé Idempotency-Key. Après un timeout, conservez exactement la même clé et le même corps. Pour lire une opération, remplacez l’identifiant d’exemple par celui reçu à la création. Vérifiez toujours les montants et les bénéficiaires avant l’envoi.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": \"100\",\n  \"currency\": \"XOF\",\n  \"provider\": \"ORANGE_MONEY\",\n  \"recipient\": {\n    \"phone_number\": \"{{payout_phone_number}}\"\n  },\n  \"client_reference\": \"abc123XYZ\",\n  \"reason\": \"Test Payout OM\",\n  \"metadata\": {\n    \"source\": \"postman\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const data=pm.response.json();",
                  "pm.test('Known HTTP response',()=>pm.expect(pm.request.method==='POST'?[201,400,401,403,409,422,429,503]:[200,400,401,403,404,429,503]).to.include(pm.response.code));",
                  "if(pm.response.code===201||pm.response.code===200){",
                  " pm.test('Payout response contract',()=>{",
                  "  pm.expect(data.object).to.eql('payout');pm.expect(data.environment).to.eql(pm.variables.get('expected_environment'));",
                  "  pm.expect(['WAVE','ORANGE_MONEY']).to.include(data.provider);pm.expect(data.currency).to.eql('XOF');pm.expect(typeof data.livemode).to.eql('boolean');",
                  "  pm.expect(data.id).to.match(/^po_[a-f0-9]{32}$/);pm.expect(data.transaction_id).to.match(/^txn_[a-f0-9]{32}$/);",
                  "  pm.expect(['PENDING','PROCESSING','UNKNOWN','SUCCEEDED','FAILED']).to.include(data.status);",
                  "  for(const key of ['amount','faygaw_partner_fee','total_amount']){pm.expect(typeof data[key]).to.eql('string');pm.expect(data[key]).to.match(/^(0|[1-9][0-9]*)$/);}",
                  "  pm.expect(BigInt(data.amount)>0n).to.eql(true);",
                  "  if(pm.request.method==='POST'){const sent=JSON.parse(pm.variables.replaceIn(pm.request.body.raw));pm.expect(pm.response.code).to.eql(201);pm.expect(data.amount).to.eql(sent.amount);pm.expect(data.client_reference).to.eql(sent.client_reference);pm.expect(data.provider).to.eql(sent.provider);}",
                  "  else{pm.expect(pm.response.code).to.eql(200);pm.expect(data.id).to.eql(pm.variables.replaceIn(pm.request.url.toString()).split('?')[0].split('/').pop());}",
                  "  if(data.recipient!==undefined)pm.expect(data.recipient.phone_number).to.match(/^221[1-9][0-9]{8}$/);",
                  " });",
                  "}else{pm.test('Structured API error',()=>{pm.expect(typeof data.error.code).to.eql('string');pm.expect(typeof data.error.request_id).to.eql('string');});}"
                ]
              }
            }
          ]
        },
        {
          "name": "Lire le Payout — payout:read",
          "request": {
            "method": "GET",
            "url": "{{base_url}}/payouts/po_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              }
            ],
            "description": "Le Payout est disponible avec Wave et Orange Money au Sénégal, en XOF. amount correspond au montant à envoyer au bénéficiaire. Idempotency-Key est obligatoire et client_reference doit être unique. Utilisez un numéro international sans +, par exemple 221771234567. Pour Orange Money : provider: ORANGE_MONEY. HTTP 201 CREATED avec status PROCESSING confirme la création ; le résultat final est asynchrone. Consultez GET /payouts/{payout_id} ou écoutez payout.succeeded et payout.failed. Un rejeu idempotent conserve la réponse initiale. UNKNOWN signifie que le résultat final du payout n’est pas encore déterminé. Ne soumettez pas une opération de remplacement. Continuez à récupérer le payout existant jusqu’à obtention d’un statut terminal. Modifiez les valeurs d’exemple directement dans les requêtes. Pour une nouvelle opération, changez la référence et la clé Idempotency-Key. Après un timeout, conservez exactement la même clé et le même corps. Pour lire une opération, remplacez l’identifiant d’exemple par celui reçu à la création. Vérifiez toujours les montants et les bénéficiaires avant l’envoi."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const data=pm.response.json();",
                  "pm.test('Known HTTP response',()=>pm.expect(pm.request.method==='POST'?[201,400,401,403,409,422,429,503]:[200,400,401,403,404,429,503]).to.include(pm.response.code));",
                  "if(pm.response.code===201||pm.response.code===200){",
                  " pm.test('Payout response contract',()=>{",
                  "  pm.expect(data.object).to.eql('payout');pm.expect(data.environment).to.eql(pm.variables.get('expected_environment'));",
                  "  pm.expect(['WAVE','ORANGE_MONEY']).to.include(data.provider);pm.expect(data.currency).to.eql('XOF');pm.expect(typeof data.livemode).to.eql('boolean');",
                  "  pm.expect(data.id).to.match(/^po_[a-f0-9]{32}$/);pm.expect(data.transaction_id).to.match(/^txn_[a-f0-9]{32}$/);",
                  "  pm.expect(['PENDING','PROCESSING','UNKNOWN','SUCCEEDED','FAILED']).to.include(data.status);",
                  "  for(const key of ['amount','faygaw_partner_fee','total_amount']){pm.expect(typeof data[key]).to.eql('string');pm.expect(data[key]).to.match(/^(0|[1-9][0-9]*)$/);}",
                  "  pm.expect(BigInt(data.amount)>0n).to.eql(true);",
                  "  if(pm.request.method==='POST'){pm.expect(pm.response.code).to.eql(201);pm.expect(data.amount).to.eql(JSON.parse(pm.variables.replaceIn(pm.request.body.raw)).amount);pm.expect(data.client_reference).to.eql(JSON.parse(pm.variables.replaceIn(pm.request.body.raw)).client_reference);}",
                  "  else{pm.expect(pm.response.code).to.eql(200);pm.expect(data.id).to.eql(pm.variables.replaceIn(pm.request.url.toString()).split('?')[0].split('/').pop());}",
                  "  if(data.recipient!==undefined)pm.expect(data.recipient.phone_number).to.match(/^221[1-9][0-9]{8}$/);",
                  " });",
                  "}else{pm.test('Structured API error',()=>{pm.expect(typeof data.error.code).to.eql('string');pm.expect(typeof data.error.request_id).to.eql('string');});}"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Refund",
      "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.",
      "item": [
        {
          "name": "Créer un Refund — refund:write",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/refunds",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "example-refund-order-001"
              }
            ],
            "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.\n\nUne indisponibilité ou un délai dépassé pendant la vérification du remboursement ne constitue pas un échec du Refund et ne produit pas refund.failed. Le résultat reste UNKNOWN et les réservations sont conservées tant que la restitution n’est pas confirmée. Les vérifications reprennent automatiquement dans la fenêtre de 72 heures. À son terme, utilisez la relance manuelle du même Refund ; ne créez pas une demande de remplacement. Continuez le suivi par GET et traitez refund.succeeded dès sa confirmation.\nAn unavailable or timed-out refund verification is not a failed Refund and does not emit refund.failed. The result stays UNKNOWN and reservations are retained while restitution remains unconfirmed. Verification resumes automatically within the 72-hour window. After that window, use the same Refund’s manual retry; do not create a replacement request. Keep tracking with GET and process refund.succeeded when confirmed.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "Refund created — processing",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Created",
              "code": 201,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"id\": \"ref_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n  \"object\": \"refund\",\n  \"transaction_id\": \"txn_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n  \"original_transaction_id\": \"txn_cccccccccccccccccccccccccccccccc\",\n  \"checkout_id\": \"co_dddddddddddddddddddddddddddddddd\",\n  \"environment\": \"SANDBOX\",\n  \"livemode\": true,\n  \"status\": \"PROCESSING\",\n  \"refunded_amount\": \"100\",\n  \"refunded_faygaw_partner_fee\": \"1\",\n  \"currency\": \"XOF\",\n  \"provider\": \"WAVE\",\n  \"provider_transaction_id\": null,\n  \"client_reference\": \"REFUND-001\",\n  \"reason\": \"Customer request\",\n  \"created_at\": \"2026-10-31T12:00:00Z\",\n  \"updated_at\": \"2026-10-31T12:00:00Z\",\n  \"completed_at\": null,\n  \"failure_code\": null\n}"
            },
            {
              "name": "invalid-field",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"invalid-field\",\n    \"message\": \"Invalid Refund fields.\",\n    \"request_id\": \"req_refund_example\",\n    \"details\": [\n      {\n        \"field\": \"body\"\n      }\n    ]\n  }\n}"
            },
            {
              "name": "idempotency-key-required",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"idempotency-key-required\",\n    \"message\": \"The request is invalid.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "refund-original-not-found",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Not Found",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"refund-original-not-found\",\n    \"message\": \"Refund not found.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "idempotency-conflict",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"idempotency-conflict\",\n    \"message\": \"The request conflicts with an existing operation.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "refund-already-exists",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"refund-already-exists\",\n    \"message\": \"The request conflicts with an existing operation.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "refund-reference-conflict",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"refund-reference-conflict\",\n    \"message\": \"The request conflicts with an existing operation.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "refund-original-not-paid",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unprocessable Entity",
              "code": 422,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"refund-original-not-paid\",\n    \"message\": \"The payment request was declined.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "refund-insufficient-partner-funds",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unprocessable Entity",
              "code": 422,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"refund-insufficient-partner-funds\",\n    \"message\": \"The payment request was declined.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "refund-provider-unavailable",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unprocessable Entity",
              "code": 422,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"refund-provider-unavailable\",\n    \"message\": \"The payment request was declined.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "rate-limit-exceeded",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Too Many Requests",
              "code": 429,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"rate-limit-exceeded\",\n    \"message\": \"The request limit has been reached.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "SERVICE_UNAVAILABLE",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "example-refund-order-001"
                  }
                ],
                "description": "Full refund uniquement. Fournissez le transaction_id FAYGAW du Checkout payé, une client_reference unique et une Idempotency-Key. Le montant et le provider sont déterminés par FAYGAW. Après une réponse perdue, réutilisez exactement la même clé et le même corps ; consultez GET pour le statut actuel. UNKNOWN ne signifie pas échec. Les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund.\n\nFull refund only. Send the paid Checkout FAYGAW transaction_id, a unique client_reference and an Idempotency-Key. FAYGAW determines the amount and provider. After a lost response, reuse the exact key and body; use GET for the current status. UNKNOWN is not a failure. Original FAYGAW fees are returned to the Partner.\n\nHTTP 201 confirms creation, not completion. Reuse the same Idempotency-Key and body after a lost response; use GET for the current status. UNKNOWN requires continued tracking. Error responses contain error.code, error.message and error.request_id; keep request_id for support. Main creation errors: 400 idempotency-key-required / invalid-field, 404 refund-original-not-found, 409 idempotency-conflict / refund-already-exists / refund-reference-conflict, 422 refund-original-not-paid / refund-insufficient-partner-funds / refund-provider-unavailable. Both methods may return 401, 403, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"transaction_id\": \"txn_REPLACE_WITH_PAID_CHECKOUT_TRANSACTION_ID\",\n  \"client_reference\": \"refund-order-001\",\n  \"reason\": \"Customer request\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Service Unavailable",
              "code": 503,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"SERVICE_UNAVAILABLE\",\n    \"message\": \"The service is temporarily unavailable.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Consulter un Refund — refund:read",
          "request": {
            "method": "GET",
            "url": "{{base_url}}/refunds/ref_REPLACE_WITH_REFUND_ID",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              }
            ],
            "description": "Statut actuel : PROCESSING, UNKNOWN, SUCCEEDED ou FAILED. / Current status: PROCESSING, UNKNOWN, SUCCEEDED or FAILED.\n\nHTTP 200 confirms a successful read, not a successful refund. GET may return 400 invalid-request, 401 authentication-required / invalid-api-key, 403 forbidden-scope / ip-not-allowed, 404 refund-not-found, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE. Inspect error.code, error.message and error.request_id.\n\nUne indisponibilité ou un délai dépassé pendant la vérification du remboursement ne constitue pas un échec du Refund et ne produit pas refund.failed. Le résultat reste UNKNOWN et les réservations sont conservées tant que la restitution n’est pas confirmée. Les vérifications reprennent automatiquement dans la fenêtre de 72 heures. À son terme, utilisez la relance manuelle du même Refund ; ne créez pas une demande de remplacement. Continuez le suivi par GET et traitez refund.succeeded dès sa confirmation.\nAn unavailable or timed-out refund verification is not a failed Refund and does not emit refund.failed. The result stays UNKNOWN and reservations are retained while restitution remains unconfirmed. Verification resumes automatically within the 72-hour window. After that window, use the same Refund’s manual retry; do not create a replacement request. Keep tracking with GET and process refund.succeeded when confirmed."
          },
          "response": [
            {
              "name": "Current Refund",
              "originalRequest": {
                "method": "GET",
                "url": "{{base_url}}/refunds/ref_REPLACE_WITH_REFUND_ID",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  }
                ],
                "description": "Statut actuel : PROCESSING, UNKNOWN, SUCCEEDED ou FAILED. / Current status: PROCESSING, UNKNOWN, SUCCEEDED or FAILED.\n\nHTTP 200 confirms a successful read, not a successful refund. GET may return 400 invalid-request, 401 authentication-required / invalid-api-key, 403 forbidden-scope / ip-not-allowed, 404 refund-not-found, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE. Inspect error.code, error.message and error.request_id."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"id\": \"ref_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n  \"object\": \"refund\",\n  \"transaction_id\": \"txn_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n  \"original_transaction_id\": \"txn_cccccccccccccccccccccccccccccccc\",\n  \"checkout_id\": \"co_dddddddddddddddddddddddddddddddd\",\n  \"environment\": \"SANDBOX\",\n  \"livemode\": true,\n  \"status\": \"SUCCEEDED\",\n  \"refunded_amount\": \"100\",\n  \"refunded_faygaw_partner_fee\": \"1\",\n  \"currency\": \"XOF\",\n  \"provider\": \"WAVE\",\n  \"provider_transaction_id\": null,\n  \"client_reference\": \"REFUND-001\",\n  \"reason\": \"Customer request\",\n  \"created_at\": \"2026-10-31T12:00:00Z\",\n  \"updated_at\": \"2026-10-31T12:00:10Z\",\n  \"completed_at\": \"2026-10-31T12:00:10Z\",\n  \"failure_code\": null\n}"
            },
            {
              "name": "refund-not-found",
              "originalRequest": {
                "method": "GET",
                "url": "{{base_url}}/refunds/ref_REPLACE_WITH_REFUND_ID",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  }
                ],
                "description": "Statut actuel : PROCESSING, UNKNOWN, SUCCEEDED ou FAILED. / Current status: PROCESSING, UNKNOWN, SUCCEEDED or FAILED.\n\nHTTP 200 confirms a successful read, not a successful refund. GET may return 400 invalid-request, 401 authentication-required / invalid-api-key, 403 forbidden-scope / ip-not-allowed, 404 refund-not-found, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE. Inspect error.code, error.message and error.request_id."
              },
              "status": "Not Found",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"refund-not-found\",\n    \"message\": \"Refund not found.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "rate-limit-exceeded",
              "originalRequest": {
                "method": "GET",
                "url": "{{base_url}}/refunds/ref_REPLACE_WITH_REFUND_ID",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  }
                ],
                "description": "Statut actuel : PROCESSING, UNKNOWN, SUCCEEDED ou FAILED. / Current status: PROCESSING, UNKNOWN, SUCCEEDED or FAILED.\n\nHTTP 200 confirms a successful read, not a successful refund. GET may return 400 invalid-request, 401 authentication-required / invalid-api-key, 403 forbidden-scope / ip-not-allowed, 404 refund-not-found, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE. Inspect error.code, error.message and error.request_id."
              },
              "status": "Too Many Requests",
              "code": 429,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"rate-limit-exceeded\",\n    \"message\": \"The request limit has been reached.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            },
            {
              "name": "SERVICE_UNAVAILABLE",
              "originalRequest": {
                "method": "GET",
                "url": "{{base_url}}/refunds/ref_REPLACE_WITH_REFUND_ID",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  }
                ],
                "description": "Statut actuel : PROCESSING, UNKNOWN, SUCCEEDED ou FAILED. / Current status: PROCESSING, UNKNOWN, SUCCEEDED or FAILED.\n\nHTTP 200 confirms a successful read, not a successful refund. GET may return 400 invalid-request, 401 authentication-required / invalid-api-key, 403 forbidden-scope / ip-not-allowed, 404 refund-not-found, 429 rate-limit-exceeded and 503 SERVICE_UNAVAILABLE. Inspect error.code, error.message and error.request_id."
              },
              "status": "Service Unavailable",
              "code": 503,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "key": "X-Request-Id",
                  "value": "req_refund_example"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"SERVICE_UNAVAILABLE\",\n    \"message\": \"The service is temporarily unavailable.\",\n    \"request_id\": \"req_refund_example\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Relancer un Refund après 72 h — refund:write",
          "request": {
            "method": "POST",
            "url": "{{base_url}}/refunds/ref_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/retry",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "manual-refund-retry-001"
              }
            ],
            "description": "Les reprises automatiques durent au maximum 72 heures après la demande initiale. Un refus de tentative ne rend pas le paiement définitivement non remboursable. Après cette limite, relancez le même Refund avec POST /v1/refunds/{refund_id}/retry et une nouvelle Idempotency-Key : une seule tentative, sans nouveau cycle automatique de 72 heures. Réutilisez la même clé et le même corps après une réponse perdue. HTTP 202 confirme la prise en charge, pas le remboursement ; consultez GET. Un Refund déjà SUCCEEDED ne déclenche aucun nouvel envoi. Aucun nouveau frais FAYGAW ; restitution des montants confirmée seulement par SUCCEEDED.\n\nAutomatic retries run for at most 72 hours from the original request. A refused attempt does not make the payment permanently non-refundable. After that limit, retry the same Refund with POST /v1/refunds/{refund_id}/retry and a new Idempotency-Key: one attempt, without opening another automatic 72-hour cycle. Reuse the same key and body after a lost response. HTTP 202 acknowledges acceptance, not completion; use GET. An already SUCCEEDED Refund triggers no new provider send. No new FAYGAW fee; amounts are confirmed returned only at SUCCEEDED.\n\nErrors: 400 idempotency-key-required / refund-retry-body-invalid; 404 refund-not-found; 409 refund-retry-not-due / refund-retry-in-progress / idempotency-conflict. Common 401/403/429/503 responses include error.code, error.message and error.request_id.\n\nUne indisponibilité ou un délai dépassé pendant la vérification du remboursement ne constitue pas un échec du Refund et ne produit pas refund.failed. Le résultat reste UNKNOWN et les réservations sont conservées tant que la restitution n’est pas confirmée. Les vérifications reprennent automatiquement dans la fenêtre de 72 heures. À son terme, utilisez la relance manuelle du même Refund ; ne créez pas une demande de remplacement. Continuez le suivi par GET et traitez refund.succeeded dès sa confirmation.\nAn unavailable or timed-out refund verification is not a failed Refund and does not emit refund.failed. The result stays UNKNOWN and reservations are retained while restitution remains unconfirmed. Verification resumes automatically within the 72-hour window. After that window, use the same Refund’s manual retry; do not create a replacement request. Keep tracking with GET and process refund.succeeded when confirmed.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "Manual retry accepted",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds/ref_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/retry",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "manual-refund-retry-001"
                  }
                ],
                "description": "Les reprises automatiques durent au maximum 72 heures après la demande initiale. Un refus de tentative ne rend pas le paiement définitivement non remboursable. Après cette limite, relancez le même Refund avec POST /v1/refunds/{refund_id}/retry et une nouvelle Idempotency-Key : une seule tentative, sans nouveau cycle automatique de 72 heures. Réutilisez la même clé et le même corps après une réponse perdue. HTTP 202 confirme la prise en charge, pas le remboursement ; consultez GET. Un Refund déjà SUCCEEDED ne déclenche aucun nouvel envoi. Aucun nouveau frais FAYGAW ; restitution des montants confirmée seulement par SUCCEEDED.\n\nAutomatic retries run for at most 72 hours from the original request. A refused attempt does not make the payment permanently non-refundable. After that limit, retry the same Refund with POST /v1/refunds/{refund_id}/retry and a new Idempotency-Key: one attempt, without opening another automatic 72-hour cycle. Reuse the same key and body after a lost response. HTTP 202 acknowledges acceptance, not completion; use GET. An already SUCCEEDED Refund triggers no new provider send. No new FAYGAW fee; amounts are confirmed returned only at SUCCEEDED.\n\nErrors: 400 idempotency-key-required / refund-retry-body-invalid; 404 refund-not-found; 409 refund-retry-not-due / refund-retry-in-progress / idempotency-conflict. Common 401/403/429/503 responses include error.code, error.message and error.request_id.",
                "body": {
                  "mode": "raw",
                  "raw": "{}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Accepted",
              "code": 202,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"ref_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n  \"object\": \"refund\",\n  \"transaction_id\": \"txn_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n  \"original_transaction_id\": \"txn_cccccccccccccccccccccccccccccccc\",\n  \"checkout_id\": \"co_dddddddddddddddddddddddddddddddd\",\n  \"environment\": \"SANDBOX\",\n  \"livemode\": true,\n  \"status\": \"UNKNOWN\",\n  \"refunded_amount\": \"100\",\n  \"refunded_faygaw_partner_fee\": \"1\",\n  \"currency\": \"XOF\",\n  \"provider\": \"WAVE\",\n  \"provider_transaction_id\": null,\n  \"client_reference\": \"REFUND-001\",\n  \"reason\": \"Customer request\",\n  \"created_at\": \"2026-10-31T12:00:00Z\",\n  \"updated_at\": \"2026-11-03T12:01:00Z\",\n  \"completed_at\": null,\n  \"failure_code\": null\n}"
            },
            {
              "name": "Automatic window still active",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds/ref_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/retry",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "manual-refund-retry-001"
                  }
                ],
                "description": "Les reprises automatiques durent au maximum 72 heures après la demande initiale. Un refus de tentative ne rend pas le paiement définitivement non remboursable. Après cette limite, relancez le même Refund avec POST /v1/refunds/{refund_id}/retry et une nouvelle Idempotency-Key : une seule tentative, sans nouveau cycle automatique de 72 heures. Réutilisez la même clé et le même corps après une réponse perdue. HTTP 202 confirme la prise en charge, pas le remboursement ; consultez GET. Un Refund déjà SUCCEEDED ne déclenche aucun nouvel envoi. Aucun nouveau frais FAYGAW ; restitution des montants confirmée seulement par SUCCEEDED.\n\nAutomatic retries run for at most 72 hours from the original request. A refused attempt does not make the payment permanently non-refundable. After that limit, retry the same Refund with POST /v1/refunds/{refund_id}/retry and a new Idempotency-Key: one attempt, without opening another automatic 72-hour cycle. Reuse the same key and body after a lost response. HTTP 202 acknowledges acceptance, not completion; use GET. An already SUCCEEDED Refund triggers no new provider send. No new FAYGAW fee; amounts are confirmed returned only at SUCCEEDED.\n\nErrors: 400 idempotency-key-required / refund-retry-body-invalid; 404 refund-not-found; 409 refund-retry-not-due / refund-retry-in-progress / idempotency-conflict. Common 401/403/429/503 responses include error.code, error.message and error.request_id.",
                "body": {
                  "mode": "raw",
                  "raw": "{}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"refund-retry-not-due\",\n    \"message\": \"The request conflicts with an existing operation.\",\n    \"request_id\": \"req_refund_retry_example\"\n  }\n}"
            },
            {
              "name": "Invalid retry body",
              "originalRequest": {
                "method": "POST",
                "url": "{{base_url}}/refunds/ref_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/retry",
                "header": [
                  {
                    "key": "Authorization",
                    "value": "Bearer {{api_key}}"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Idempotency-Key",
                    "value": "manual-refund-retry-001"
                  }
                ],
                "description": "Les reprises automatiques durent au maximum 72 heures après la demande initiale. Un refus de tentative ne rend pas le paiement définitivement non remboursable. Après cette limite, relancez le même Refund avec POST /v1/refunds/{refund_id}/retry et une nouvelle Idempotency-Key : une seule tentative, sans nouveau cycle automatique de 72 heures. Réutilisez la même clé et le même corps après une réponse perdue. HTTP 202 confirme la prise en charge, pas le remboursement ; consultez GET. Un Refund déjà SUCCEEDED ne déclenche aucun nouvel envoi. Aucun nouveau frais FAYGAW ; restitution des montants confirmée seulement par SUCCEEDED.\n\nAutomatic retries run for at most 72 hours from the original request. A refused attempt does not make the payment permanently non-refundable. After that limit, retry the same Refund with POST /v1/refunds/{refund_id}/retry and a new Idempotency-Key: one attempt, without opening another automatic 72-hour cycle. Reuse the same key and body after a lost response. HTTP 202 acknowledges acceptance, not completion; use GET. An already SUCCEEDED Refund triggers no new provider send. No new FAYGAW fee; amounts are confirmed returned only at SUCCEEDED.\n\nErrors: 400 idempotency-key-required / refund-retry-body-invalid; 404 refund-not-found; 409 refund-retry-not-due / refund-retry-in-progress / idempotency-conflict. Common 401/403/429/503 responses include error.code, error.message and error.request_id.",
                "body": {
                  "mode": "raw",
                  "raw": "{}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"error\": {\n    \"code\": \"refund-retry-body-invalid\",\n    \"message\": \"The request is invalid.\",\n    \"request_id\": \"req_refund_retry_example\"\n  }\n}"
            }
          ]
        }
      ]
    }
  ]
}
