{
  "info": {
    "_postman_id": "07b383b0-4776-4391-bc39-041c72b7b182",
    "name": "SOAMTAR API v1 — Sierra Leone",
    "description": "Collection officielle de l'API marchand SOAMTAR (Orange Money Sierra Leone, leone SLE).\n\n1. Renseignez `api_key` (clé secrète de test `sk_test_…` d'abord) dans les variables de la collection.\n2. Lancez « Santé » pour valider la clé, puis « Créer un paiement ».\n3. Le client reçoit la demande Orange Money sur son téléphone et valide avec son PIN.\n\nMontants : chaînes à 2 décimales (`\"150.00\"`). Téléphones : E.164 `+232` + 8 chiffres.\nSignature HMAC facultative : mettez `sign_requests` à `true` pour ajouter `Soamtar-Timestamp` / `Soamtar-Signature`.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_key}}",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "// Signature HMAC facultative (Soamtar-Signature = v1=HMAC_SHA256(timestamp.METHOD.path, api_key)).",
          "if (pm.collectionVariables.get('sign_requests') === 'true' && pm.request.method !== 'GET') {",
          "  const ts = Math.floor(Date.now() / 1000).toString();",
          "  const path = pm.request.url.getPath().replace(/^\\//, '');",
          "  const secret = pm.collectionVariables.get('api_key');",
          "  const sig = CryptoJS.HmacSHA256(`${ts}.${pm.request.method}.${path}`, secret).toString(CryptoJS.enc.Hex);",
          "  pm.request.headers.upsert({ key: 'Soamtar-Timestamp', value: ts });",
          "  pm.request.headers.upsert({ key: 'Soamtar-Signature', value: `v1=${sig}` });",
          "}"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "base_url",
      "value": "https://app.so-amtar.com/v1",
      "type": "string",
      "description": "URL de l'API"
    },
    {
      "key": "api_key",
      "value": "",
      "type": "string",
      "description": "Clé API secrète (sk_test_… ou sk_live_…). Rangez-la plutôt dans un environnement Postman (type « secret », valeur courante uniquement) : les variables de collection sont synchronisées et partagées avec la collection. Ne jamais l’exposer côté navigateur."
    },
    {
      "key": "payer_phone",
      "value": "+23276000001",
      "type": "string",
      "description": "Numéro Orange Money du payeur (E.164)"
    },
    {
      "key": "sign_requests",
      "value": "false",
      "type": "string",
      "description": "true pour signer les requêtes POST"
    },
    {
      "key": "transaction_id",
      "value": "",
      "type": "string",
      "description": "Rempli automatiquement"
    },
    {
      "key": "reference",
      "value": "",
      "type": "string",
      "description": "Rempli automatiquement"
    },
    {
      "key": "payout_id",
      "value": "",
      "type": "string",
      "description": "Rempli automatiquement"
    },
    {
      "key": "webhook_url",
      "value": "https://example.com/webhooks/soamtar",
      "type": "string",
      "description": "Votre URL de webhook (HTTPS publique)"
    },
    {
      "key": "refund_id",
      "value": "",
      "type": "string",
      "description": "Rempli automatiquement"
    },
    {
      "key": "payout_ref",
      "value": "PAYOUT-001",
      "type": "string",
      "description": "Référence du prochain payout. Changez-la pour chaque nouveau payout : renvoyer la requête réutilise la même Idempotency-Key et ne peut pas payer deux fois."
    },
    {
      "key": "refund_seq",
      "value": "1",
      "type": "string",
      "description": "Numéro du remboursement sur ce paiement (1, 2, …). Incrémentez-le pour un nouveau remboursement partiel ; un renvoi garde la même Idempotency-Key."
    }
  ],
  "item": [
    {
      "name": "Compte",
      "description": "Vérifier la clé et l'état du compte.",
      "item": [
        {
          "name": "Santé",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/health",
            "description": "Valide la clé API."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Fournisseurs disponibles",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/providers",
            "description": ""
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Solde",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/balance",
            "description": ""
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Paiements (encaissements)",
      "description": "Demande de paiement Orange Money envoyée sur le téléphone du client.",
      "item": [
        {
          "name": "Créer un paiement",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "url": "{{base_url}}/payments",
            "description": "Réponse en attente (`pending`) : le client confirme ensuite avec son PIN.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"merchant_ref\": \"ORDER-{{$timestamp}}\",\n  \"amount\": \"150.00\",\n  \"currency\": \"SLE\",\n  \"provider\": \"orange_money_sl\",\n  \"phone\": \"{{payer_phone}}\",\n  \"description\": \"Commande de test\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "const tx = json.data || json;",
                  "pm.test('Paiement créé', () => pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]));",
                  "if (tx.id) pm.collectionVariables.set('transaction_id', tx.id);",
                  "if (tx.reference) pm.collectionVariables.set('reference', tx.reference);"
                ]
              }
            }
          ]
        },
        {
          "name": "Détail d'un paiement",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/payments/{{transaction_id}}",
            "description": ""
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Statut par référence",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/status/{{reference}}",
            "description": ""
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Revérifier auprès d'Orange",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "url": "{{base_url}}/payments/{{transaction_id}}/verify",
            "description": ""
          }
        },
        {
          "name": "Lister les paiements",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/payments",
            "description": ""
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Paiements sortants",
      "description": "Envoi d'argent vers un compte Orange Money (payout).",
      "item": [
        {
          "name": "Créer un paiement sortant",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "payout-{{payout_ref}}"
              }
            ],
            "url": "{{base_url}}/payouts",
            "description": "",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"merchant_ref\": \"{{payout_ref}}\",\n  \"amount\": \"50.00\",\n  \"currency\": \"SLE\",\n  \"provider\": \"orange_money_sl\",\n  \"recipient\": {\n    \"phone\": \"{{payer_phone}}\",\n    \"name\": \"Aminata Kamara\"\n  },\n  \"description\": \"Paiement fournisseur\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "const tx = json.data || json;",
                  "pm.test('Paiement sortant créé', () => pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]));",
                  "if (tx.id) pm.collectionVariables.set('payout_id', tx.id);"
                ]
              }
            }
          ]
        },
        {
          "name": "Détail d'un paiement sortant",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/payouts/{{payout_id}}",
            "description": ""
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Lister les paiements sortants",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/payouts",
            "description": ""
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Remboursements",
      "description": "Remboursement d'un paiement réussi : le montant est recrédité sur le numéro Orange Money du payeur et débité de votre solde. Clé avec le scope `can_refund`. Sandbox : `success` immédiat ; Orange Money : `processing` puis webhook `refund.success` / `refund.failed`.",
      "item": [
        {
          "name": "Créer un remboursement",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "refund-{{transaction_id}}-{{refund_seq}}"
              }
            ],
            "url": "{{base_url}}/refunds",
            "description": "Omettez `amount` pour rembourser tout le montant restant. `transaction_id` accepte l'id ou la référence TXN-… (alias `payment_id`).",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"transaction_id\": \"{{transaction_id}}\",\n  \"amount\": \"10.00\",\n  \"reason\": \"customer_request\",\n  \"description\": \"Remboursement partiel\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "const refund = json.data || json;",
                  "pm.test('Remboursement créé', () => pm.response.to.have.status(201));",
                  "if (refund.id) pm.collectionVariables.set('refund_id', refund.id);"
                ]
              }
            }
          ]
        },
        {
          "name": "Détail d'un remboursement",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/refunds/{{refund_id}}",
            "description": "Accepte l'id ou la référence REF-…."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Lister les remboursements",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/refunds?transaction_id={{transaction_id}}&per_page=25",
            "description": "Filtres : `status`, `transaction_id`, `per_page`, `page`."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Webhooks",
      "description": "Notifications envoyées à votre serveur (payment.success, payment.failed…).",
      "item": [
        {
          "name": "Lister les endpoints",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{base_url}}/webhooks",
            "description": ""
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Créer un endpoint",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{base_url}}/webhooks",
            "description": "`subscribed_events` est optionnel. Événements disponibles : payment.success, payment.failed, payment.cancelled, payment.expired, payment.refunded, payment.partially_refunded, payout.success, payout.failed, payout.cancelled, refund.success, refund.failed, payout_request.submitted, payout_request.approved, payout_request.rejected, payout_request.completed, payout_request.failed.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"{{webhook_url}}\",\n  \"subscribed_events\": [\n    \"payment.success\",\n    \"payment.failed\",\n    \"payout.success\",\n    \"payout.failed\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Envoyer un webhook de test",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{base_url}}/webhooks/test",
            "description": "Envoie l'événement `webhook.test` (signé avec le secret de l'endpoint) à tous vos endpoints actifs de l'environnement de la clé, quels que soient leurs abonnements. 400 `no_webhook_endpoints` si aucun endpoint actif."
          }
        }
      ]
    }
  ]
}