Proposition API REST SI Paiement

Proposition d'API REST avec naming anglais plus clair et schema unifie

Cette page propose une version plus REST de l'API actuelle Dépot / Retrait, avec un vocabulaire anglais plus clair, des routes homogènes et un schéma unifié.

Constats sur l'existant

  • La ressource métier est dupliquée entre deposit-requests et withdrawal-requests, alors que le cycle de vie est le même.
  • Plusieurs noms sont ambigus pour un consommateur externe : externalId, payableId, requestPartnerId, partnerBillId.
  • La route de mise à jour sert uniquement à annuler une demande via PATCH { "status": "CANCELED" }.
  • Certains champs mélangent format technique et métier : amountInCents, serviceFeesInCents, authorizationId concaténé.
  • Les timestamps ne suivent pas une convention unique : creationDate, expirationDate, processingDateTime, sentDate.
  • Les payloads exposent des codes internes peu lisibles comme CSH et CBA.

Principes de design retenus

  • Une seule ressource métier : cash-requests
  • URLs en kebab-case, payloads JSON en camelCase
  • Noms de ressources au pluriel
  • Timestamps normalisés avec le suffixe At
  • Références partenaire explicites avec le suffixe Reference
  • Montants regroupés dans un objet amount
  • Identifiants techniques séparés des identifiants métier

Resource model propose

La ressource principale devient une demande de mouvement d'especes :

  • DEPOSIT pour un depot d'especes
  • WITHDRAWAL pour un retrait d'especes

Cette approche évite d'avoir deux familles d'endpoints presque identiques.

Routes proposees

API FDJ Services exposee au partenaire

MethodRouteUsage
POST/v2/partners/{partnerId}/products/{productId}/cash-requestsCreer une demande de depot ou de retrait
GET/v2/partners/{partnerId}/products/{productId}/cash-requestsLister les demandes
GET/v2/partners/{partnerId}/products/{productId}/cash-requests/{cashRequestId}Consulter une demande
DELETE/v2/partners/{partnerId}/products/{productId}/cash-requests/{cashRequestId}Annuler une demande

API partenaire exposee a FDJ Services

MethodRouteUsage
POST/v1/cash-authorizationsValider la faisabilite d'une operation avant passage en point de vente
POST/v1/webhooks/cash-transactionsRecevoir la notification de transaction finalisee

Pourquoi ces routes sont plus REST

  • cash-requests represente une vraie ressource metier persistante.
  • POST cree une demande.
  • GET liste ou retourne une ressource.
  • DELETE annule la demande au lieu d'utiliser un PATCH uniquement pour changer le statut.
  • Le type d'operation est dans le payload, pas dans le nom de la route.

Schema propose

Create cash request

{
  "partnerReference": "f7c78c0c-bf7b-4ec2-8a8e-acde52431111",
  "operationType": "DEPOSIT",
  "amount": {
    "value": 25000,
    "currency": "EUR"
  },
  "customer": {
    "partnerCustomerReference": "customer_001",
    "type": "INDIVIDUAL",
    "firstName": "Jeanne",
    "lastName": "Martin",
    "birthDate": "1998-07-12",
    "birthCity": "Paris",
    "countryOfResidence": "FR"
  }
}

Cash request response

{
  "id": "7dc272f2-b383-4d95-bbac-3b8db23d2c0d",
  "partnerId": "123",
  "productId": "45",
  "partnerReference": "f7c78c0c-bf7b-4ec2-8a8e-acde52431111",
  "operationType": "DEPOSIT",
  "status": "PENDING",
  "amount": {
    "value": 25000,
    "currency": "EUR"
  },
  "fee": {
    "value": 0,
    "currency": "EUR"
  },
  "customer": {
    "partnerCustomerReference": "customer_001"
  },
  "qrCode": {
    "format": "EMVCO",
    "content": "000201010212..."
  },
  "createdAt": "2026-01-19T14:08:34.043Z",
  "expiresAt": "2026-01-19T15:08:34.032Z"
}

List cash requests response

{
  "items": [
    {
      "id": "7dc272f2-b383-4d95-bbac-3b8db23d2c0d",
      "partnerReference": "f7c78c0c-bf7b-4ec2-8a8e-acde52431111",
      "operationType": "DEPOSIT",
      "status": "PENDING",
      "amount": {
        "value": 25000,
        "currency": "EUR"
      },
      "createdAt": "2026-01-19T14:08:34.043Z",
      "expiresAt": "2026-01-19T15:08:34.032Z"
    }
  ],
  "nextCursor": "YXJyYXljb25uZWN0aW9uOjE5"
}

Filtres recommandes pour le listing

Query paramTypeDescription
cursorstringCurseur de pagination
limitnumberNombre maximum d'elements
partnerReferencestringReference metier du partenaire
operationTypestringDEPOSIT ou WITHDRAWAL
statusstringPENDING, COMPLETED, CANCELLED, EXPIRED
createdFromstringDate ISO 8601 de debut
createdTostringDate ISO 8601 de fin

Customer schema recommande

Individual customer

{
  "partnerCustomerReference": "customer_001",
  "type": "INDIVIDUAL",
  "firstName": "Jeanne",
  "lastName": "Martin",
  "birthDate": "1998-07-12",
  "birthCity": "Paris",
  "countryOfResidence": "FR"
}

Business customer

{
  "partnerCustomerReference": "company_001",
  "type": "BUSINESS",
  "legalName": "ACME SAS",
  "registrationNumber": "123456789",
  "countryOfResidence": "FR"
}

Authorization callback propose

Au lieu d'un endpoint generique et peu structure, la recommandation est de creer une ressource d'autorisation.

Request

POST /v1/cash-authorizations

{
  "cashRequestId": "7dc272f2-b383-4d95-bbac-3b8db23d2c0d",
  "partnerReference": "f7c78c0c-bf7b-4ec2-8a8e-acde52431111",
  "operationType": "DEPOSIT",
  "amount": {
    "value": 25000,
    "currency": "EUR"
  },
  "customer": {
    "partnerCustomerReference": "customer_001"
  },
  "expiresAt": "2026-01-19T15:08:34.032Z"
}

Response

{
  "authorizationId": "0c9aabf7-f380-4ad7-a3fd-5e18f9365e30",
  "status": "APPROVED",
  "approvedAt": "2026-01-19T14:09:01.000Z",
  "expiresAt": "2026-01-19T15:08:34.032Z"
}

Recommendation de comportement

  • 201 Created si l'autorisation est accordee
  • 409 Conflict si l'operation n'est pas autorisee dans l'etat courant
  • 422 Unprocessable Entity si une regle metier refuse l'operation

Webhook event propose

Le webhook actuel peut etre rendu plus lisible avec un event envelope stable et un objet metier explicite.

Route recommandee

POST /v1/webhooks/cash-transactions

Payload

{
  "eventId": "5fed0137-a5d7-4ad2-a822-6ae4d768fa8f",
  "eventType": "cash-transaction.completed",
  "occurredAt": "2026-01-19T15:08:34.032Z",
  "deliveredAt": "2026-01-19T15:08:36.000Z",
  "data": {
    "transactionId": "8ffea5f0-8796-4d12-a9fd-eb14c55dbfdb",
    "cashRequestId": "7dc272f2-b383-4d95-bbac-3b8db23d2c0d",
    "partnerId": "123",
    "productId": "45",
    "partnerReference": "f7c78c0c-bf7b-4ec2-8a8e-acde52431111",
    "partnerCustomerReference": "customer_001",
    "operationType": "DEPOSIT",
    "amount": {
      "value": 25000,
      "currency": "EUR"
    },
    "fee": {
      "value": 0,
      "currency": "EUR"
    },
    "paymentMethod": "CASH",
    "pointOfSaleId": "2f4fc4ee-d166-47e9-8e8c-1c0e8ed2d26a",
    "processedAt": "2026-01-19T15:08:34.032Z",
    "expectedSettlementAt": "2026-01-20T00:00:00.000Z",
    "metadata": {}
  }
}

Mapping recommande entre l'existant et la proposition

ExistantProposition
datamatrixPartnerIdpartnerId
datamatrixProductIdproductId
payableIdcashRequestId
externalIdpartnerReference
customer.externalIdcustomer.partnerCustomerReference
requestPartnerIdpartnerReference
customerExternalIdcustomer.partnerCustomerReference
creationDatecreatedAt
expirationDateexpiresAt
processingDateTimeprocessedAt
sentDatedeliveredAt
serviceFeesInCentsfee.value
partnerBillIdpartnerReference
partnerCustomerIdpartnerCustomerReference
freeFieldsmetadata
paymentMethod: CSHpaymentMethod: CASH
paymentMethod: CBApaymentMethod: CARD

Points de schema a corriger en priorite

1. Ne plus concatener plusieurs identifiants dans authorizationId

Au lieu de :

{
  "authorizationId": "serviceRequestId/qrCodeId"
}

Utiliser :

{
  "authorizationId": "0c9aabf7-f380-4ad7-a3fd-5e18f9365e30",
  "serviceRequestId": "6d0e6a82-6d69-4f6d-9942-54bca4f2206d",
  "qrCodeId": "a2c1d77b-b60f-4a52-8a1e-2bbeb2f0963b"
}

2. Normaliser les montants

Au lieu de dupliquer amountInCents et serviceFeesInCents, utiliser un modele commun :

{
  "amount": {
    "value": 25000,
    "currency": "EUR"
  },
  "fee": {
    "value": 0,
    "currency": "EUR"
  }
}

3. Homogeneiser les statuts

Statuts recommandes :

  • PENDING
  • COMPLETED
  • CANCELLED
  • EXPIRED

4. Clarifier les codes d'erreur

Exemples de renommage :

ExistantProposition
UNKNOWN_PAYABLECASH_REQUEST_NOT_FOUND
BILL_ALREADY_PAIDREQUEST_ALREADY_COMPLETED
PAYMENT_IN_PROGRESSREQUEST_PROCESSING
MAX_BILL_AMOUNT_KOAMOUNT_ABOVE_MAXIMUM
MIN_BILL_AMOUNT_KOAMOUNT_BELOW_MINIMUM
PAYER_ACCOUNT_KOINVALID_CUSTOMER_ACCOUNT

5. Uniformiser le format d'erreur

{
  "error": {
    "code": "REQUEST_ALREADY_COMPLETED",
    "message": "The cash request has already been completed.",
    "details": {},
    "requestId": "0994b43f-1dbf-4f76-9d91-41f9f25cf5a6"
  }
}

Strategie de migration recommandee

  • Conserver l'API actuelle en /v1
  • Exposer la nouvelle version en /v2
  • Garder le meme moteur metier cote back-end
  • Mapper les anciens noms vers le nouveau contrat au niveau d'adaptation
  • Deprecier ensuite les routes deposit-requests et withdrawal-requests

Recommandation finale

Si l'objectif est d'ameliorer la lisibilite sans changer le metier, la meilleure evolution est :

  1. unifier deposit et withdrawal dans cash-requests
  2. renommer les identifiants avec un vocabulaire metier explicite
  3. remplacer l'annulation par DELETE
  4. normaliser les montants, timestamps, statuts et erreurs

Cette proposition reste proche de l'existant, donc elle limite le cout de migration tout en rendant l'API beaucoup plus claire pour une equipe externe.

On this page