{
  "info": {
    "name": "FAYGAW — Payout Wave et Orange Money SANDBOX",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "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. ⚠ Les opérations effectuées avec une clé SANDBOX peuvent utiliser des fonds réels. 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."
  },
  "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": "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. ⚠ Les opérations effectuées avec une clé SANDBOX peuvent utiliser des fonds réels. 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. ⚠ Les opérations effectuées avec une clé SANDBOX peuvent utiliser des fonds réels. 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. ⚠ Les opérations effectuées avec une clé SANDBOX peuvent utiliser des fonds réels. 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');});}"
            ]
          }
        }
      ]
    }
  ]
}
