openapi: 3.0.1
info:
  title: Spike API for Exchanges
  description: |
    # Spike API for Exchanges
    The Spike API facilitates two key scenarios:
    1. Transfer of funds from a Payment Account at a Partner Bank to a Trading Account at a Partner Exchange.
    2. Transfer of funds from a Trading Account at a Partner Exchange to a Payment Account at a Partner Bank.

    ## API structure
    This specification outlines the APIs that both Spike and the Exchange must implement.
    - **Spike Transfers** and **Spike Accounts** Tags: APIs that Spike must implement.
    - **Exchange Webhooks** Tag: APIs that the Exchange must implement.

    Please note that the Exchange APIs may be customized; if so, an Annex detailing these changes is prepared and shared with the Exchange.

    ## Glossary
    - **Partner Bank** - any financial institution authorised to offer payment accounts and related services to Spike and their clients.
    - **Partner Exchanges** - any exchange authorised to offer crypto exchange and related services to users in a territory.
    - **Payment Account**: an account held by a user at a Partner Bank, managed through this API.
    - **Settlement Account**: an account held by a Partner Exchange at a Partner Bank, managed through this API.
    - **Trading Account**: an account held by a user at the Partner Exchange, not managed through this API.
    - **Spike Transfer**: a transfer of funds between a Payment Account and a Trading Account via a Settlement Account, consisting of two parts: pay-in and pay-out.

    ## Implementation details
    Users can initiate transfers through the Spike App or directly from the Exchange.\
    The initial transfer authorisation is processed through the Exchange, ensuring that the Exchange is aware of and authorises all transfers.\
    All accounts involved in each transfer must belong to the same user, and the API will enforce this condition.

    ### Accounts and default values
    Users may hold multiple Payment Accounts; the account involved in the transfer must be specified in the API call.\
    Exchanges may hold multiple Settlement Accounts; the account involved in the transfer must be specified in the API call.\
    A dedicated API is available to list Payment Accounts.

    ## Payment Account to Trading Account flow
    ![image](https://uploads-ssl.webflow.com/636e03adc0125c6eba441920/66bdcd36820d0fed1eec8cc8_payment-to-trading.png)

    ## Trading Account to Payment Account flow
    ![image](https://uploads-ssl.webflow.com/636e03adc0125c6eba441920/66bdcd3d8d256df073c77d8f_trading-to-payment.png)

    ## API authorisation
    To authenticate API requests to Spike, a signature-based approach using asymmetric encryption is employed:
    1. **Encryption**: Spike uses Sha256WithRSA with 4096-bits keys.
    2. **Signature Generation**: Required for the entire request body, with the signature sent in a separate `Signature` header in base64 format.
    4. **Replay Protection**: Managed via HTTPS/TLS, so a nonce is not required (nonce validation is a known bottleneck).
    5. **Timestamp Validation**: Requests older than 5 minutes will be ignored. The Timestamp must be provided in the `Timestamp` header.
    6. **Client Identification**: The `KeyID` header is used to identify the client by the request.

    Given that Spike uses asymmetric encryption, it’s essential to verify that the signature was created by the intended client. The client must generate the signature using their private key, and Spike will verify it using the client’s public key.

    ### Keys configuration
    1. **Public Key Provision**: Discuss and establish the preferred channel for sharing your public key with Spike.
    2. **Key Pair Generation**:
    ```
    openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:4096
    ```
    3. **Public Key Sharing**: Provide your public key to the Spike Team via the agreed channel.
    4. **KeyID Assignment**: Upon receipt, you will receive a `KeyID`, which must be included as a header in your API requests to identify the client.

    **Note**: Keep your private key secure and never share it.
    ### Signature headers
    For each API request:
    1. Sign the request payload using your private key to generate a unique signature.
    2. Include this signature in the Signature header.
    3. The signature can be created as follows:
        1. Use the format `KeyID:Timestamp:RequestBody` to generate the payload (use empty String if RequestBody is missing)
        2. Hash the payload using Sha256.
        3. Sign it with your RSA private key.
        4. Encode it in base64.

    ### Request handling
    When Spike’s API server receives your request, it will:
    1. Retrieve your registered public key using the KeyID.
    2. Verify the signature against the request payload and timestamp.
    3. If the signature is valid, your request will be processed.

    This process ensures secure and authenticated communication between your application and the Spike API, protecting your data and interactions on our platform.

    ## API testing with Postman
    We have created a Postman Collection to simplify interaction with our API. This Collection includes pre-built requests to test various API endpoints. Additionally, a sandbox environment is pre-configured for safe experimentation without impacting production data.
    ### How to use the Postman Collection
    #### 1. Download the Postman Collection:
    Download the [Postman Collection File](https://one.spikeapp.cool/docs/SpikeTransfersAPI.postman_collection.json)
    #### 2. Import the Collection into Postman:
    1. Open the Postman application
    2. Click on "File" > "Import"
    3. Select the downloaded collection file and click "Open".
    4. The collection will now appear in your Postman workspace.

    #### 3. Access the Sandbox environment:
    The collection is configured with environment variables pointing to our sandbox environment.
    All requests made through the collection will automatically be routed to the sandbox environment.
    #### 4. Execute API requests:
    Browse the collection to locate the API endpoint you want to test.
    Select the desired request and review the associated parameters and headers.
    Click "Send" to execute the request. You will receive a response from the sandbox environment, allowing you to review the API’s functionality.

    **Note**: The first request to run is **"Init request to get jsrsasign lib"**.
    #### 5. Customise and Experiment:
    Feel free to modify request parameters and headers to test different scenarios. You can save these modifications or create new requests within the collection for further testing.
  version: 1.0.0
  x-logo:
    url: https://uploads-ssl.webflow.com/636e03adc0125c6eba441920/66bc8c855a8e03ad4712cd24_spike-sm.svg
    backgroundColor: '#FFFFFF'
    altText: Spike logo
tags:
  - name: Spike Transfers
    description: The Spike Transfers functionality enables transfers between Payment and Trading Accounts. Spike implements this API.
  - name: Spike Accounts
    description: The Spike Accounts functionality provides access to account details related to the Exchange customer. Spike implements this API.
  - name: Exchange Webhooks
    description: Exchange Webhooks provide the ability to handle transfer-related events and authorizations triggered by Spike. The Exchange implements this API.
paths:
  /v1/transfers/paymentToTrading:
    post:
      tags:
        - Spike Transfers
      operationId: paymentToTrading
      description: Initiates a transfer from a Payment Account to a Trading Account. This can either be triggered after invoking /v1/spikeTransfers/paymentToTradingAuthorisation or directly by the Exchange. A specific settlement account may be indicated. Transfer status updates are provided via the /v1/webhooks/spikeTransferUpdate endpoint.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentToTradingTransferRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SpikeTransfer'
        '404':
          $ref: '#/components/responses/ErrorResponse'
  /v1/transfers/tradingToPayment:
    post:
      tags:
        - Spike Transfers
      operationId: tradingToPayment
      description: Initiates a transfer from a Trading Account to a Payment Account. Similar to payment transfers, this can either follow a call to /v1/spikeTransfers/tradingToPaymentAuthorisation or be initiated by the Exchange. A specific settlement account may be indicated. Transfer status updates are provided via the /v1/webhooks/spikeTransferUpdate endpoint.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TradingToPaymentTransferRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SpikeTransfer'
        '404':
          $ref: '#/components/responses/ErrorResponse'
  /v1/transfers/getTransfers:
    post:
      tags:
        - Spike Transfers
      operationId: getTransfers
      description: Retrieves a list of Spike Transfers, with optional filters for time-based slicing and additional query parameters to refine the results.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GetSpikeTransfersRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SpikeTransfer'
  /v1/accounts/getPaymentAccounts:
    post:
      tags:
        - Spike Accounts
      operationId: getPaymentAccounts
      description: Returns a list of all Payment Accounts linked to a Spike user. Additional filters can be applied through query parameters.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GetPaymentAccountsRequest'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SpikePaymentAccount'
  /v1/accounts/getSettlementAccounts:
    post:
      tags:
        - Spike Accounts
      operationId: getSettlementAccounts
      description: Returns a list of Settlement Accounts associated with the Exchange. Additional filters can be applied through query parameters.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GetSettlementAccountsRequest'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SettlementAccount'
  /v1/spikeTransfers/paymentToTradingAuthorisation:
    post:
      tags:
        - Exchange Webhooks
      operationId: paymentToTradingAuthorisation
      description: This endpoint is invoked by Spike when a customer requests to transfer funds from a Payment Account to a Trading Account. Upon authorisation, the corresponding transfer should be initiated via the /v1/spikeTransfers/paymentToTrading endpoint using the provided spikeTransferId.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentToTradingAuthorisationRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthorisationResponse'
        '500':
          $ref: '#/components/responses/ErrorResponse'
  /v1/spikeTransfers/tradingToPaymentAuthorisation:
    post:
      tags:
        - Exchange Webhooks
      operationId: tradingToPaymentAuthorisation
      description: This endpoint is invoked by Spike when a customer requests a transfer from a Trading Account to a Payment Account. After authorisation, the /v1/spikeTransfers/tradingToPayment endpoint should be called with the provided spikeTransferId.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TradingToPaymentAuthorisationRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthorisationResponse'
        '500':
          $ref: '#/components/responses/ErrorResponse'
  /v1/webhooks/spikeTransferUpdate:
    post:
      tags:
        - Exchange Webhooks
      operationId: spikeTransferUpdate
      description: This webhook is triggered by Spike to notify the Exchange about changes in the state of a transfer (both initialisation and completion). In case of failure, Spike will retry the request with exponential backoff.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SpikeTransfer'
        required: true
      responses:
        '200':
          description: OK
components:
  schemas:
    PaymentSystem:
      title: PaymentSystem
      type: string
      description: Specific Bank or Payment Provider, which used for these transfers
      enum:
        - INCORE
        - MATCHMOVE
    Amount:
      title: Amount
      type: object
      required:
        - currency
        - value
      properties:
        currency:
          description: ISO-4217 format
          type: string
          example: USD
        value:
          type: number
          example: 100
    PaymentToTradingTransferRequest:
      title: PaymentToTradingTransferRequest
      type: object
      required:
        - idempotencyKey
        - paymentSystem
        - amount
        - paymentAccountId
        - tradingAccountId
      properties:
        idempotencyKey:
          type: string
          format: uuid
          description: Unique identifier to prevent duplicate operations
          example: c8b62cac-3e1d-455a-aa08-852dd877c34a
        spikeTransferId:
          description: optional, Id which was passed to /v1/spikeTransfers/paymentToTradingAuthorisation
          type: string
          format: uuid
          example: 67f2ab48-14af-406f-bb7a-986117829429
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
        paymentAccountId:
          description: Source Spike Payment Account Id, from the list provided in API
          type: string
          format: uuid
          example: 31243822-db41-4866-80c7-8cb1c27e3066
        tradingAccountId:
          description: Destination Exchange Trading Account Id
          type: string
          example: '789654523'
        settlementAccountId:
          description: Destination Payment System Account Id. If not provided, default will be used.
          type: string
          example: '8965413658'
        amount:
          $ref: '#/components/schemas/Amount'
    SpikeTransferStatus:
      title: SpikeTransferStatus
      type: string
      enum:
        - CREATED
        - PENDING
        - COMPLETED
        - FAILED
    PaymentSystemTransferDetails:
      title: PaymentSystemTransferDetails
      type: object
      required:
        - id
      properties:
        id:
          description: Payment System specific Id
          type: string
          example: '5896485'
        details:
          type: object
          description: Payment System specific details
    SpikeTransferDirection:
      title: SpikeTransferDirection
      type: string
      enum:
        - FROM_BANK_TO_EXCHANGE
        - FROM_EXCHANGE_TO_BANK
    SpikeTransfer:
      title: SpikeTransfer
      type: object
      required:
        - spikeTransferId
        - paymentSystem
        - status
        - amount
        - direction
      properties:
        spikeTransferId:
          description: Spike-Specific Id
          type: string
          format: uuid
          example: 2acd1508-34f2-4c9b-9ac6-0bfeda79af84
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
        settlementAccountId:
          description: Settlement account Id involved in the transfer
          type: string
          example: '8965413658'
        status:
          $ref: '#/components/schemas/SpikeTransferStatus'
        payoutPartTransferDetails:
          description: Payment System specific Id of payout part. Available for PENDING transfers
          $ref: '#/components/schemas/PaymentSystemTransferDetails'
        payinPartTransferDetails:
          description: Payment System specific Id of payin part. Optional for PENDING transfers, required for COMPLETED
          $ref: '#/components/schemas/PaymentSystemTransferDetails'
        amount:
          $ref: '#/components/schemas/Amount'
        paymentAccountId:
          description: Source Spike Payment Account Id, from the list provided in API
          type: string
          format: uuid
          example: 31243822-db41-4866-80c7-8cb1c27e3066
        tradingAccountId:
          description: Destination Exchange Trading Account Id
          type: string
          example: '789654523'
        direction:
          $ref: '#/components/schemas/SpikeTransferDirection'
        transferUpdateTime:
          type: integer
          description: Timestamp of the last update
          format: int64
          example: 1723233345
    Error:
      title: Error
      type: object
      properties:
        code:
          type: integer
          format: int64
          description: List of exact codes will be defined and provided later
        message:
          type: string
          example: Account not found
        traceId:
          type: string
          example: 66bc7e6cce533e5c89de9592a38a5709
        details:
          type: object
          description: Will be defined and described together with code field
      required:
        - code
    TradingToPaymentTransferRequest:
      title: TradingToPaymentTransferRequest
      type: object
      required:
        - idempotencyKey
        - paymentSystem
        - amount
        - paymentAccountId
        - tradingAccountId
      properties:
        idempotencyKey:
          type: string
          format: uuid
          description: Unique identifier to prevent duplicate operations
          example: c8b62cac-3e1d-455a-aa08-852dd877c34a
        spikeTransferId:
          description: optional, Id which was passed to /v1/spikeTransfers/tradingToPaymentAuthorisation
          type: string
          format: uuid
          example: 67f2ab48-14af-406f-bb7a-986117829429
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
        paymentAccountId:
          description: Destination Spike Payment Account Id, from the list provided in API
          type: string
          format: uuid
          example: 31243822-db41-4866-80c7-8cb1c27e3066
        tradingAccountId:
          description: Source Exchange Trading Account Id
          type: string
          example: '789654523'
        settlementAccountId:
          description: Source Payment System Account Id. If not provided, default will be used.
          type: string
          example: '8965413658'
        amount:
          $ref: '#/components/schemas/Amount'
    GetSpikeTransfersRequest:
      title: GetSpikeTransfersRequest
      type: object
      required:
        - createdTimeFrom
      properties:
        createdTimeFrom:
          type: integer
          format: int64
          example: 1723233345
        createdTimeTo:
          type: integer
          format: int64
          example: 1723433345
        limit:
          type: integer
          default: 100
          minimum: 1
          maximum: 1000
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
        ids:
          type: array
          description: list of Spike-specific Ids
          example:
            - 2777fd25-900d-4fd6-9489-92d2e13e0498
            - 8b76029a-f25c-453f-bb6c-b9accc349a5c
          items:
            type: string
            format: uuid
        status:
          $ref: '#/components/schemas/SpikeTransferStatus'
        direction:
          $ref: '#/components/schemas/SpikeTransferDirection'
    GetPaymentAccountsRequest:
      title: GetPaymentAccountsRequest
      type: object
      required:
        - exchangeSpecificClientId
      properties:
        id:
          type: string
          format: uuid
          description: Spike Specific Id
          example: 2acd1508-34f2-4c9b-9ac6-0bfeda79af84
        exchangeSpecificClientId:
          type: string
          example: '49623548'
        currency:
          description: ISO-4217 format
          type: string
          example: USD
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
    SpikePaymentAccount:
      title: SpikePaymentAccount
      type: object
      required:
        - id
        - currency
        - paymentSystem
      properties:
        id:
          description: Spike-Specific Id
          type: string
          format: uuid
          example: 2acd1508-34f2-4c9b-9ac6-0bfeda79af84
        currency:
          type: string
          description: ISO-4217 format
          example: USD
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
        availableBalance:
          $ref: '#/components/schemas/Amount'
    GetSettlementAccountsRequest:
      title: GetSettlementAccountsRequest
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Spike Specific Id
          example: 2acd1508-34f2-4c9b-9ac6-0bfeda79af84
        currency:
          type: string
          description: ISO-4217 format
          example: USD
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
    SettlementAccount:
      title: SettlementAccount
      type: object
      required:
        - id
        - currency
        - paymentSystem
      properties:
        id:
          description: Spike-Specific Id
          type: string
          format: uuid
          example: 2acd1508-34f2-4c9b-9ac6-0bfeda79af84
        currency:
          description: ISO-4217 format
          type: string
          example: USD
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
        availableBalance:
          $ref: '#/components/schemas/Amount'
    PaymentToTradingAuthorisationRequest:
      title: PaymentToTradingAuthorisationRequest
      type: object
      required:
        - spikeTransferId
        - amount
        - paymentSystem
        - paymentAccountId
        - tradingAccountId
      properties:
        spikeTransferId:
          description: Spike-Specific Id, must be used as idempotency key
          type: string
          format: uuid
          example: 67f2ab48-14af-406f-bb7a-986117829429
        amount:
          $ref: '#/components/schemas/Amount'
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
        paymentAccountId:
          description: Source Spike Payment Account Id, from the list provided in API operationId:getPaymentAccounts
          type: string
          format: uuid
          example: 31243822-db41-4866-80c7-8cb1c27e3066
        tradingAccountId:
          description: Destination Exchange Trading Account Id
          type: string
          example: '789654523'
        settlementAccountId:
          description: Destination Payment System Account Id
          type: string
          example: '8965413658'
    AuthorisationResponse:
      title: AuthorisationResponse
      type: object
      required:
        - status
      properties:
        status:
          type: string
          enum:
            - APPROVED
            - REJECTED
        details:
          description: Optional metadata
          type: object
    TradingToPaymentAuthorisationRequest:
      title: TradingToPaymentAuthorisationRequest
      type: object
      required:
        - spikeTransferId
        - amount
        - paymentSystem
        - paymentAccountId
        - tradingAccountId
      properties:
        spikeTransferId:
          type: string
          format: uuid
          description: Spike-Specific Id, must be used as idempotency key
          example: 2acd1508-34f2-4c9b-9ac6-0bfeda79af84
        amount:
          $ref: '#/components/schemas/Amount'
        paymentSystem:
          $ref: '#/components/schemas/PaymentSystem'
        paymentAccountId:
          description: Destination Spike Payment Account Id, from the list provided in API
          type: string
          format: uuid
          example: 31243822-db41-4866-80c7-8cb1c27e3066
        tradingAccountId:
          description: Source Exchange Trading Account Id
          type: string
          example: '789654523'
        settlementAccountId:
          description: Source Payment System Account Id
          type: string
          example: '8965413658'
  responses:
    ErrorResponse:
      description: Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
