Swap API

This page will describes how the swap API functions and how users can connect.

The Titan Swap API requires an API token to work. Please contact info@titandex.io or reach out to the team on telegram/discord.

This API primarily allows for requesting quotes for token swaps and receiving a live stream of quotes with updated simulated results.

There are two primary layers of the API:

  • The Remote Procedure Call (RPC) protocol, which defines what requests the client can make and what responses they should expect for each request.

  • The Wire Protocol, which defines what messages can be sent by each side of the connection and how they are formatted.

WebSocket Connections

The server MAY define a specific endpoint to connect to for WebSocket connections (e.g. /api/v1/ws).

All Titan API messages will be sent as Binary messages. Attempts to send Text messages SHOULD be ignored.

The client and server SHOULD support all valid non-data WebSocket message types (e.g. Ping, Pong, etc) appropriately.

Protocol Negotiation

When initiating a WebSocket connection the server, the client MUST specify the protocol version and encoding schemes it supports in the Sec-WebSocket-Protocol header. The values SHOULD be specified in order of preference, with the most preferred protocol and encoding scheme specified first.

All protocol values for version 1 begin with v1.api.titan.ag. The protocol may be suffixed with a plus (+) character followed by an encoding scheme.

Currently supported compression schemes are:

  • zstd - Compression using zstd.

  • brotli - Compression using brotli.

  • gzip - Compression using gzip.

Valid protocol values for version 1 are:

  • v1.api.titan.ag

  • v1.api.titan.ag+zstd

  • v1.api.titan.ag+brotli

  • vi.api.titan.ag+gzip

If an encoding scheme is specified, the encoding is applied to all messages AFTER encoding and BEFORE decoding.

Authentication

The server MAY require authentication from users in order to connect. Version 1 requires any authentication to occur up-front, before requests are made.

If authentication is required, the client MUST submit valid credentials via the Authentication header.

The standard authentication scheme will be Json Web Tokens (JWTs) submitted as one of the following:

  • A Bearer token in the Authorization header (recommended).

  • Via the auth query parameter for clients that cannot specify headers (e.g. browsers).

Submitted JWTs MUST be signed by an authority trusted by the servers and MUST include the following claims:

  • iss: Issuer of the JWT

  • sub: JWT subject, which should be a unique identifier for the user being authenticated.

  • aud: JWT audience, must be api.titan.ag.

  • exp: Token expiration time, connections will be refused if the specified time is in the past.

  • iat: When the JWT was issued. The server MUST reject tokens with issue times in the future.

JWTs MAY include the following registered claims:

  • nbf: If set, connections will be refused if the specified time is in the future.

  • jti: If set and supported by the server, only one connection per unique jti value will be accepted.

JWTs MAY include the following custom claims.

  • https://api.titan.ag/upk_b58: A Solana public key, encoded as a Base58 string. If set, this will be used as the user's public key for transaction generation. Any attempt by the user to submit a different key or change the default key to a different value will result in an error.

Remote Procedure Call Interface

When a client connects to a Titan API server, the basic way it interacts is by making requests with a given set of parameters, and expecting a result (success or error) for that request.

Procedure
Parameters
Response Type
Stream Type

GetInfo

GetInfoRequest

ServerInfo

None

NewSwapQuoteStream

SwapQuoteRequest

QuoteSwapStreamResponse

SwapQuotes

StopStream

StopStreamRequest

StopStreamResponse

None

GetVenues

GetVenuesRequest

VenueInfo

ListProviders

ListProvidersRequest

ProviderInfo[]

Functionally, a connection to the API server could be modeled as something like:

Data Format

The basic data format utilized for serialization of messages is MessagePack.

Objects/structs MUST be encoded as maps unless otherwise specified. This is to allow for additional fields to be added without breaking compatibility with previous versions of the protocol.

Field names in objects/structs are encoded in camelCase unless otherwise specified.

Optional Data

If a value is optional, its type will be represented in Rust as Option<T> and TypeScript as T? or T | null;

If the optional data is a field in an object/struct, it MAY be omitted from the serialized map if missing. Otherwise a missing optional value SHOULD be encoded as nil (0xc0). This will be decoded as None in Rust and null in TypeScript.

Simple Enumerations

Simple enumerations, which are those without associated data, are encoded as strings matching the names of the enumeration values exactly.

For example:

The above enumeration values would be encoded as the strings "ExactIn" and "ExactOut".

Complex Enumerations

Complex enumerations, which are those with associated data, are encoded as single-value maps, mapping the name of the enumeration value to the associated data.

If the associated data consists of a single item, the value is that data.

If the associated data consists of multiple items, the value is an array containing the associated data items.

For example, given the following enumeration:

The following are valid encodings of Complex, presented as JSON for readability:

The above enumeration could be represented in TypeScript as a union:

Binary Data

Binary data SHOULD be encoded using one of the bin formats defined in MessagePack.

In Rust, the following types are encoded as binary data unless otherwise specified:

  • Vec<u8> for a variable-sized byte array.

  • [u8; N] for a fixed sized byte array, where N is an integer giving the number of bytes.

In TypeScript, the following types are encoded as binary:

  • Uint8Array

  • ArrayBuffer

TypeScript has no easy way of specifying the size of a byte array, so please look at the Rust types for information regarding that.

Wire Protocol Type Definitions

Common Types

Pubkey

Solana public keys are encoded as 32-byte binary data. Pubkeys SHOULD be encoded using the bin 8 format for size. Thus, all public keys will start with c4 20 followed by the public key data.

For example, the WSOL public key So11111111111111111111111111111111111111112 would be encoded as (spaces added for legibility):

c4 20 069b8857feab8184fb687f634618c035dac439dc1aeb3b5598a0f00000000001

In TypeScript, this would be represented as a Uint8Array of length 32.

AccountMeta

Solana Account metadata is commonly used for instruction data, so it has a custom encoding with shorter field names to save space.

The Rust definition for the encoded form is:

In TypeScript:

Instruction

Similar to AccountMeta, instructions are also heavily used and thus have a custom encoding with shorter field names to save space.

SwapMode

Represents how an amount in a swap request should be interpreted.

If ExactIn, the user is requesting that an exact number of input tokens should be swapped. In this case, any slippage will occur on the output token.

If ExactOut, the user is requesting that an exact number of output tokens should be obtained from the swap. In this case, any slippage will occur on the input token. Not all providers support ExactOut swaps.

Client Requests

Requests from the client are represented as follows:

These map to the following request data:

  • GetInfo -> GetInfoRequest

  • NewSwapQuoteStream -> SwapQuoteRequest

  • StopStream -> SwapStreamRequest

  • GetVenues -> GetVenuesRequest

  • ListProviders -> ListProvidersRequest

  • GetSwapPrice -> SwapPriceRequest

GetInfoRequest

This request currently has no options, so the associated data is represented as an empty object. This is done to allow expansion in the future.

The server SHOULD ignore any unknown fields.

SwapQuoteRequest

Parameters for requesting quotes for a swap.

In TypeScript:

StopStreamRequest

Parameters for requesting the end of a stream of data.

Once sent to the server, the client MAY receive one or more StreamData messages for the stream if any were already queued for sending, followed by a StreamEnd message indicating that no more data will be sent.

In TypeScript:

GetVenuesRequest

Parameters for requesting the list of known venues used by the various providers.

In TypeScript:

ListProvidersRequest

Parameters for requesting the list of configured quote providers.

In TypeScript:

SwapPriceRequest

Available since: Protocol version 1.2.0

Parameters for requesting the price of swapping directly between two tokens.

The user chooses the input and output mints, as well as the amount of tokens to price at. The server then finds the best direct route it can and uses the simulated amount out to determine the price.

Rust data types:

In TypeScript:

Server Messages

Responses from the server are represented as follows:

In TypeScript:

ServerInfo

Represents information about the server any any setting defaults, limits, and other configurable parameters.

In TypeScript:

QuoteSwapStreamResponse

Response containing information about a new stream of swap quotes.

Currently mainly contains information about settings that may have been filled in by the server.

A response with this payload SHOULD also contain a StreamStart.

In TypeScript:

StopStreamResponse

Response sent by the server that indicates that a stream has been successfully stopped. The client may still receive one or more StreamData messages for this stream if they have already been queued, followed by a StreamEnd message.

In TypeScript:

VenueInfo

Venue information sent by the server as part of a response to a GetVenuesRequest.

In TypeScript:

ProviderInfo

Provider information sent by the server as part of a response to a ListProvidersRequest.

In TypeScript:

SwapPrice

Available since: Protocol version 1.2.0

Information about a priced swap. The amount out was generated by finding the best direct swap between the input and output tokens at the given amount in, and then simulating the swap to determine the amount out. This effectively allows the users to compute the price between the two tokens.

Rust data type:

TypeScript type:

Stream Data

This section details the various types of data that may be streamed to the client by the server.

SwapQuotes

A set of quotes for a swap transaction, including the instructions necessary to execute the swap.

In TypeScript:

Last updated