Idempotency for SEN and Internal Transfer

SEN and Internal transfers now have a new duplicate payment control in the form of an optional idempotency key which may be sent in the header. The scenarios around idempotent POST transfersen and transferinternal requests are as follows:

  1. Not Passed – It is optional, therefore if idempotency key not passed, code will run as normal to attempt POST transfer. No checks to the idempotency database (db) will occur.
  2. Key passed for first time use
    1. Check for key in db returns no records, key will get added to the db, record will initially have a status of New (1)
    2. Initiate transfer is called
      • If transfer returns with success, record updated with status of Success (2), and results from core system stored in db record and returned to customer
      • If transfer returns with a failure or exception, results are updated with a status of Fail (3), record is updated in db and error message returned in response to customer
  3. Key passed, already exists in db
    1. Check for key in db, key is found
    2. If status of found record = success, result data is deserialized to the response object and returned to the user. New transfer is not initiated. Note that only the key is evaluated; no other parameters are compared.
    3. If status of found record is not success (new or fail), Silvergate system queries GET history to check for idempotency key in core system history response. If found, success message is returned to the customer. If fail confirmed, resulting Error returned to the user (5xx server error) with the value stored in the result of the record.

In summary, we ensure exactly once delivery by separating our logic into distinct phases. All 5xx errors become retryable for client requests. 4xx errors are not technically retryable because some element of the request must be altered to achieve success, however a GUID used on a 4xx request may be reused with a corrected submission. For 2xx, once a record for an idempotency key has been written to the db, the result will always be returned from a post call with the matching id and the code will never call the payment service again as long as that key exists in the db. Database records will be deleted 7 days after initial insert.

For reference, idempotency key passed via POST transfersen and transferinternal is returned in updated GET history and extendedhistory Responses.

{ "SEQUENCE": 0, "ResponseData": [ { "RECS_RETURNED": 0, "MOREDATA": "string", "TRANSACTION": [ { "TRANDATE": "string", "TRANCD": "string", "TRANAMT": 0.0, "CHECKNBR": "string", "IDEMPOTENCYKEY": "string", "TRANDESC": "string", "TRANDESCS": "string",