NAV
shell

Introduction

Welcome to the Token Transit Bulk Purchase API.

The Token Transit Bulk Purchase API is a RESTful service that can be used to purchase transit passes for users to redeem in other apps. Where possible the API uses understandable resource identifiers, JSON-encoded responses, and well-known HTML response and error codes.

In addition to the live API, you may also access our test API by using an test API key.

Headers

The Token Transit Bulk Purchase API uses a number of common headers across the API. Some requests also require specific headers that will be mentioned separately. These should be included in each request.

List

This is a list of all headers and the endpoints for which they are useful.

Request Headers

These are all of the headers that you may need to include with requests

Header Endpoints Default Description
Token-Transit-Api-Key all N/A (Required) Authentication that also identifies your service and access
Token-Transit-Api-Version all N/A (Required) Describes which version of the API you wish to use. This document describes version
Accept-Language Fares, Agencies en-US User language for requesting results in a different language
Idempotency-Key Purchase N/A (Highly Recommended!) A key to indicate a request is a duplicate (retry) of a previous request to prevent duplicate transactions

Response headers

This is a list of important headers that might be sent back across multiple API requests.

Header Endpoints Description
Content-Type all The encoding of the response (usually application/json)
Retry-After stateful endpoints upon a 503 failure How many seconds to wait until retrying a request. A value of 0 means that the request may be retried immediately.
Access-Control-Allow-Origin all CORS is enabled on a per-developer basis. Contact Token Transit for information on enabling CORS for your platform.

API Authentication

Token Transit Bulk Purchase API uses API keys for authentication of your service. If you are integrating with us, your secret and publishable test and live API keys will be sent to you during the integration process.

To authenticate with Token Transit, you must send your API key as the Token-Transit-API-Key HTTP header like the following example:

Token-Transit-API-Key: sk_fake_1234567890abcdef

API keys have two components: key type and environment.

Key Types

There are two types of keys: publishable (publishable) and secret (secret). Publishable keys may be freely used in your app. Publishable API keys are indicated with a pk prefix to all keys. An API key has

Key Type Key Prefix Access Level Allowed Usage
Publishable (publishable) pk Agency information App or web clients
Secret (secret) sk All Backend servers only

If an endpoint restricts only certain information or is only available for use with a secret key, it will be marked as "(Requires Secret Key)".

Environments

There are three environments available as part of the Token Transit Ticketing API: fake, test, and live.

Environment Key Infix Description
fake _fake_ Fast, deterministic, stateless, fake API useful for exploring the API or automating integration tests.
test _test_ Test servers that use fake credit cards, user accounts, and test payment provider environment. Useful for testing before launch.
live _live_ Live service that should only use real accounts.

Code examples in this doc exclusively use the fake environment.

Distribution

During your integration, we will ask you to provide us with a public RSA key. We we sign your API keys and distribute them to you over e-mail or your preferred method of contact.

Retrieval and Invalidation

Once we send you a copy of your API key, it is impossible for us to re-send you your key. If you suspect a key has been compromised or you lose your API key, we will have to send you new key(s) and invalidate the old one(s).

Protocol

All calls must be made over HTTPS and include API key authentication or they will fail.

User Credentials

In addition to API keys, some endpoints also require you also create an administrative user session. User sessions are long-lasting sessions created using the Token Transit API. User sessions are returned as cookies and are created by sending a signed JWT that we can use to verify account credentials. You should use a user id (unique per user) for each of your users and that you guarantee you can map back to a user for the duration of our integration with you to used as the sub claim in your JWT.

Token Transit uses standardized JWK tools to accept and verify your JWT. The standards for this interaction are:

Token Transit requires that you send a signed JWT to create Token Transit account credentials. We will use a URL that you provide us separately to fetch your JWKs and verify the signature on each JWT we are provided.

We expect your JWTs to be short-lived (less than 10 minutes will work well with Token Transit infrastructure). We expect your JWKs to be publicly accessible at a URL that you provide us, served over HTTPS, as a JSON Web Key Set (JWKS).

Here is a list of useful Links if you are not experienced with JWTs:

Setting up your own internal tooling to support JWT and JWKS is not difficult. There are also many third party services that will assist with this such as Auth0 and AWS Cognito.

Authorization Header

User credentials should be sent using the Authorization header specifying the Bearer type. Example:

Authorization: Bearer JWTHeader.JWTClaims.JWTSignature

JWT Specification

We use the following standard claims:

Claim Required Description
iat Required Creation time of the JWT. Must be in the past.
exp Required Expiration time of the JWT (Recommended no longer than 10 minutes past creation time)
sub Required User ID of the authorized user that must be unique and that you can use to identify the authorized user.
aud Optional If specified, please set to "tokentransit.com". We will reject any requests that include this claim but specify something else. This may be helpful to specify if you are generating JWTs for another API and don't want to mix up the JWTs.
iss Optional If specified, it must be a prefix of the HTTPS address of the JWKS server you have on file. This may be helpful to specify if you have a test and live server and you want an appropriate error message indicating that the issuer is incorrect.
jti Optional Can be used to force generation of a new session. We will never duplicate a session across JTIs even if the device ID is the same.

We also use the following custom claims:

Claim Required Description
email Optional Specifies a contact method for the admininstrative account which can be used for identification of administrative account.
receipt_email Optional Specifies an email address to send the receipt to.
device_id Optional If you would like us to store a device id associated with the administrative account.

Versioning

The Token Transit Ticketing API uses a versioning system to separate breaking API changes. The Token-Transit-Api-Version header should always be set to ensure that the correct version of the API is used.

All version ids look like date strings in the format YYYY-MM-DD.

This version of the API is 2020-05-21.

JWKS Server

API implementors must provide a JWKS server endpoint that is publicly accessible. We will occasionally fetch your JWKS when neccessary or when signature verification fails. Token Transit provides an example endpoint that meets our specification and can be used for verification.

curl "https://api.tokentransit.com/testing/jwks.json"

The above command returns the following valid JWKS:

{
  "keys": [
    {
      "kty": "RSA",
      "alg": "RS256",
      "kid": "0c2c5382-cef8-4c60-bda8-16bb0771c3bc",
      "use": "sig",
      "e": "AQAB",
      "n": "odw6amrOS58r3APO4V90Rv_qS4FKn1Ri9MD6vjpFNJcQKfLeJLIdLhBPr_rUY0O5dyOd2xvv8Zc4yd4G8iWpDtO-1ShwigMARg6mlY0iHZH9l-hUKsm1x_cg3L4Tovp2SIEidhJp5MvpTodKJAtBADs6-s-YVokS3R5dQLnUy9MWpB9o_YvexR8slMzyb9wwcIJaLcFOFiJ59yRxGRfuRDn4yOttdqaKU4c8yjqbknwPPrkHGvsJHTrTgFBy2kU_vilWLKdizhfJc3xxj7GibryNclrGW7TiLy_DoRuwPf4mtfsN6RH6zZdmqISkps--j6T7lByl2thm2iw2J05Epw"
    }
  ]
}

JWT Generation

API implementors must generate signed JWTs for each user authentication. We will verify the signature of the JWT is valid and matches a key in you JWKS. Token Transit provides an example endpoint that meets our specification that can be used for verification. Note that this endpoint requires a valid public testing key to function, and will not accept live or fake keys.

curl "https://api.tokentransit.com/auth/testing/jwt" \
  -H "Token-Transit-Api-Key: sk_fake_1234567890abcXYZ" \
  -H "Token-Transit-Api-Version: 2020-05-21" \
  --data-urlencode "sub=bcfad41f" \
  --data-urlencode "email=user@example.com" \
  --data-urlencode "phone_number=+14155550123" \
  --data-urlencode "device_id=d8a942c5-a700-450d-977d-b3935ab0ea87"

The above command returns the following valid JWT:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsidG9rZW50cmFuc2l0LmNvbSJdLCJleHAiOjE1NzY3MjM4ODAsImlhdCI6MTU3NjcyMzU4MCwiaXNzIjoiaHR0cHM6Ly9hcGkudGVzdC50b2tlbnBsZXguY29tL3Rlc3RpbmcvIiwic3ViIjoiYmNmYWQ0MWYiLCJkZXZpY2VfaWQiOiJkOGE5NDJjNS1hNzAwLTQ1MGQtOTc3ZC1iMzkzNWFiMGVhODciLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20ifQ.SMt7c2eWSmeeWBZ1yQWoCb2noDKT9vFXuJe4e5ZnKcpyDd0Cu1jSDOLk37vnhKoBrTHOlW5FHJokKX6FpHOq8MREZQw0O1lRwC7px6nqHqDgv3nDgY68kEGnLDSwUoBNwv81_qIGFhJTasFKLzVYNGeZnp4SWN6Z4SnF6rkDeidAQSHIgOSEQ78OPM_5t-0L1DXaemaaj1e7VjSCpilLP-a62sBH-soXHQQVjx6y54ew0e1HFq2I4wSNc2fAXibIrfSL3FE4zXwcXZaUmoWk08-MqnhyExjKPKvmbFdC6oEsKIWE1an7D5p4USCUUXT0QFohEHQbr87ymY1WYkSKVg

Sessions

Requests to Token Transit API endpoints that require a user session will return an error with a 401 Authorization Error status code if no session cookie or valid authorization bearer token is provided. If an authorization bearer token is provided, a user_session_id cookie will be set in the response.

You may wish to use the endpoint /user/login to obtain a session id, as this endpoint has no further side effects.

Any successful request sent with a JWT (except those sent to the /user/logout endpoint) will result in the user_session_id cookie being set. The cookie may be used until the session expires. The session may expire at any time, so you should always first try a call with the user_session_id and fall back to using a JWT if the request fails with a 401 Authorization Error status code.

If you would like to forcibly destroy a session, please call /user/logout. This will block all further calls to the Token Transit Ticketing API using that session id to fail with an authorization error.

Idempotency

All requests that have the ability to modify state will be PUT, POST, DELETE, or PATCH requests. Any of these requests can include an Idempotency-Key header. The idempotency key allows for requests to be retried without duplication of side-effects. All results whether successful or not will be saved server-side allowing a later request including an Idempotency-Key to be retried. These requests will always return the same result.

If an idempotency key is included in a request then the parameters of the request must match all previous requests with that key.

You may use any UUID suitable to yourself, but we strongly recommend generating UUIDs using UUID version 4 as specified in by IETF RFC 4122. Your UUID must be no longer than 128 bytes long and must be encoded in UTF8 format. We recommend either encoding the bytes using URL-safe base 64 encoding or the standard hexadecimal format specified in IETF RFC 4122.

Because GET requests are inherently idempotent (they do not modify state), the Idempotency-Key will be ignored on all GET requests.

Errors

Token Transit uses standard HTTP codes to indicate success or failure as well as a JSON-encoded response for each error as well as a JSON response with more details.

Status Codes

Token Transit Ticketing API uses a set of standard error codes.

Status Code Name Meaning
200 Success Request was successful.
400 Bad Request Requested parameters or format were invalid.
401 Unauthorized API key, user JWT, or session ID was missing or invalid.
403 Forbidden Requested resource cannot be accesssed by API key and/or user JWT or session ID.
404 Not Found Requested resource (e.g. Path, pass ID, etc) does not exist.
408 Request Timeout A retryable error occurred. Resend request without changing Idempotency-Key header.
409 Conflict Idempotency key was already used in a previous request with different parameters.
428 Precondition Required Request won't work given current state of user account but could work if state changes.
429 Too Many Requests Your request has been rate-limited and must be retried.
500 Server Error An internal error in the Token Transit service occurred.
503 Service Unavailable An interanl error occurred that is retriable. Use the Retry-After header for guidance for when to retry.

JSON Error Response

In addition to the status code, we also return a response with the following fields:

Field Name Type Description
code string A code identifying a specific error.
message string A message to help debug the error.
param string The name of the param that is missing or invalid.
retryable boolean A boolean indicating whether the request should be retried.
type string The type of error returned.

Error Codes

Most errors have a specific error code (set in the code field) that can be used to identify the error. Below is a table of all error codes and their meanings:

Error Code Description Resolution Retryable (using same idempotency key)
agency_free_fare_day Agency is preventing passes from being purchased or activated at this time because fares are free or not required Notify user that fares are free or not required false
appengine_unexpected_error Internal retryable error code Retry request with same idempotency key true
card_declined_expired The user's card is expired Display error false
card_declined_generic The user's card was declined with no extra explanation Display error false
card_declined_insufficient_funds The user's card has insufficient funds Display error false
card_declined_radar The user's card was declined for suspicious activity detected by Token Transit's payment processor Display error. Do not inform user why card was declined. Make sure explanation is identical to card_declined_generic above. false
card_declined_retryable An retryable error occurred while processing payment Retry request with same idempotency key true
card_declined_stolen The user tried to use a card reported as stolen Display error. Do not inform user why card was declined. Make sure explanation is identical to card_declined_generic above. false
card_ineligible A card with limits on the types of purchases it can be used (e.g. commuter benefits) for was ineligible to make this purchase Display error and request user use a different card false
datastore_failure Internal non-retryable error code Abort flow, display generic error, and refresh user passes false
datastore_retryable_failure Internal retryable error code Retry request with same idempotency key true
idempotency_key_in_use A request with different parameters already used this idempotency key. Likely indicates a bug in your implementation. Make sure to send a new idempotency key if user modifies request before retrying false
internal_checks_failed Internal non-retryable error code Abort flow, display generic error, and refresh user passes. Please notify us if you encounter this error. false
order_expired An incomplete order was retried (with same idempotency key) after timeout limit Stop retrying order and rotate the idempotency key before trying again false
pass_activated Attempted to refund a pass, pass book, or pass transfer after it was activated Pass, pass book, or pass transfer cannot be refunded false
pass_refunded Attempted to refund a transfer while one of the passes was already refunded Try refunding the passes or pass books individually false
resource_not_found Invalid id (e.g. agency, fare, pass) sent in URL Likely indicates a bug in your implementation false
serious_internal_error Major internal error occurred Display error and contact Token Transit as soon as possible if hit false
stripe_idempotency_error User changed order but same idempotency key was used Likely indicates bug in your implementation. Make sure you rotate idempotency keys after receiving a non-retryable error false
stripe_idempotency_key_in_use Rare issue that might happen if the same request is sent twice in rapid succession Wait a few seconds and then retry request with identical parameters true
stripe_invalid_request An invalid Stripe parameter was sent or an internal error occurred Ensure that you are sending correct payment credentials that are associated with this account false
stripe_retryable_error A temporary error was passed through by our payment processor Retry request with same idempotency key true
stripe_unknown_error An unknown error was passed through by our payment processor Display error and/or retry with a different idempotency key false
unknown Internal non-retryable error code Display error, and notify us if you encounter this error false
url_error Internal retryable error code Retry request with same idempotency key true

Developers

A developer is an entity that uses the Token Transit Ticketing API. Generally your integration will have two developers: test and live. We provide a few endpoints to allow you to verify that your API keys work properly.

Retrieving Developer Info

Retrieves key type and developer id to verify that your key is working. Your API key uniquely identifies what partner is making the request, the environment, and what permissions may be accessed.

HTTP Request

curl "https://api.tokentransit.com/developer" \
  -H "Token-Transit-Api-Key: sk_fake_1234567890abcXYZ" \
  -H "Token-Transit-Api-Version: 2020-05-21"

The above command returns JSON structured like this

{
  "platform_id": "plat_1234567890abcXYZ",
  "platform_name": "Fake Platform",
  "owner_entity_kind": "Platform",
  "developer_id": "dev_1234567890abcXYZ",
  "api_key_type": "secret",
  "env": "fake"
}

GET /developer

HTTP Response

Field Name Type Description
platform_id string ID of your platform. A platform is the entity associated with a developer.
platform_name string The name of your platform.
developer_id string A unique id for your developer. This developer is what your API keys are associated with
api_key_type enum (as string) Either publishable or secret indicating the key type
env enum (as string) Either fake, test or live indicating the environment that is being accessed

Testing a Secret Key (Requires Secret Key)

This endpoint will return success if you are using a secret key and fail if you are using a publishable key.

HTTP Requst

curl "https://api.tokentransit.com/developer/private" \
  -H "Token-Transit-Api-Key: sk_fake_1234567890abcXYZ" \
  -H "Token-Transit-Api-Version: 2020-05-21"

The above command returns JSON structured like this

{
  "platform_id": "plat_1234567890abcXYZ",
  "platform_name": "Fake Platform",
  "owner_entity_kind": "Platform",
  "developer_id": "dev_1234567890abcXYZ",
  "api_key_type": "secret",
  "env": "fake"
}

GET /developer/private

HTTP Response

Field Name Type Description
api_key_type enum (as string) Either publishable or secret indicating the key type
developer_id string A unique id for your developer. This developer is what your API keys are associated with
env enum (as string) Either fake, test or live indicating the environment that is being accessed
platform_id string ID of your platform. A platform is the entity associated with a developer.
platform_name string The name of your platform.

Users

A user is the Token Transit representation of an account on your system. Users must be authenticated using JWTs that are signed by your service and returned to our service. We provide endpoints to fetch information about a user, generate a user session, and destroy a user session.

Generating a New User Session (Logging in) (User Authentication Required)

To obtain a user session, make a request to the login endpoint for the user and specify a signed JWT. The session ID returned in the cookie can be used in place of a JWT in any requests requiring User Authentication.

HTTP Request

curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXItY29udGFjdC1lbWFpbEB0aGlyZC1wYXJ0eS1zaXRlLmNvbSIsImF1ZCI6IlRva2VuVHJhbnNpdCIsImlzcyI6Imh0dHBzOi8vdGhpcmQtcGFydHktc2l0ZS5jb20vcHVibGljLWtleS1zaWduYXR1cmUiLCJzdWIiOiJ1bmlxdWVVc2VySUQxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1NTk0MzAyMjR9.WRYRX2PYdUmouiQgG3r_KOTB7FRaW51YotR_YYuvnTCbymmlCP_I4-Di0QzvH096H7Mjh332JUp_Zx6P-TQt-iriEjCqKkZ8_WS9lc0TYClT5jL1cviS7yaZJgJ" \
  -H "Token-Transit-Api-Key: sk_fake_1234567890abcXYZ" \
  -H "Token-Transit-Api-Version: 2020-05-21" \
  -b /tmp/tt_fake_api_cookies \
  -c /tmp/tt_fake_api_cookies \
  -X POST \
  "https://api.tokentransit.com/user/login"

The above command returns JSON structured like this

{}

POST https://api.tokentransit.com/user/login

HTTP Response

This endpoint responds with an empty JSON object response

Destroying an Existing User Session (Logging out) (User Authentication Required)

To destroy an existing user session, make a request to the logout endpoint and specify the session id.

HTTP Request

The following command assumes you have already sent a login request and saved cookies in

/tmp/tt_fake_api_cookies

curl -H "Token-Transit-Api-Key: sk_fake_1234567890abcXYZ" \
  -H "Token-Transit-Api-Version: 2020-05-21" \

  -b /tmp/tt_fake_api_cookies \
  -c /tmp/tt_fake_api_cookies \
  -X POST \
  "https://api.tokentransit.com/user/logout"

The above command returns JSON structured like this

{}

POST https://api.tokentransit.com/user/logout

Cookies

Name Required Description
user_session_id Required The session id to destroy. This will prevent any future requests from using this session id.

HTTP Response

The response will always be an empty JSON response upon success with a cookie set to delete the user_session_id cookie.

Agencies

An agency is the issuer of a pass. Fetching an agency will return the location, name, and logo of the agency.

Agency object

All endpoints in this section either return an Agency object or a list of Agency objects.

The Agency object response is defined as follows:

Field Type Description
agency_id string A unique id for the agency.
agency_name string The name of the agency that should be displayed to the user.
logo_url string A cropped and resized logo that may be used when displaying the agency.
timezone string A string containing the name of the time zone from the time zone database, such as "America/Los_Angeles".
region string A region name to display to the user.
website string The URL of the agency's website.
phone_number string A phone number for the agency for customer support or information purposes.
email string An email address for the agency for customer support or information purposes.
location object A location object composed of latitude and longitude.
location.latitude number The latitude coordinate for the center of the agency.
location.longitude number The longitude coordinate for the center of the agency.
service_alerts array An array of Alert objects.
service_alerts.header string Header for the alert in an Array object.
service_alerts.description string Description for the alert in an Array object.
service_alerts.effect ServiceAlertEffect enum Effect for the alert in an Array object.

Service Alert effects

A service alert may have one of a number of effects. The effect type may be used to change app behaviour. New effects may be added over time; you should treat unknown effect types the same as OTHER_EFFECT.

Type Meaning
FARE_FREE The agency currently does not require fares to ride, so no fares are available for purchase.
OTHER_EFFECT

Retrieving information about an agency

This endpoint fetches an Agency object using the provided agency id.

HTTP Request

curl "https://api.tokentransit.com/agency/bigbluebus" \
  -H "Token-Transit-Api-Key: sk_fake_1234567890abcXYZ" \
  -H "Token-Transit-Api-Version: 2019-05-01"

The above command returns JSON structured like this

{
  "agency_id": "bigbluebus",
  "agency_name": "Big Blue Bus",
  "location": {
    "latitude": 34.028189,
    "longitude": -118.489176
  },
  "logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
  "region": "Santa Monica, CA",
  "timezone": "America/Los_Angeles",
  "website": "https://www.bigbluebus.com"
}

GET https://api.tokentransit.com/agency/{agency_id}

Path components

Path component description
agency_id Unique identifier for the agency.

Optional Headers

Header Default Description
Accept-Language en-US Locale(s) for the user to indicate what language agency information should be returned in. This is only for information that will be shown to the user.

HTTP Response

This endpoint will return an Agency object.

Listing all agencies

All agencies may be retrieved in one RPC.

HTTP Request

curl "https://api.tokentransit.com/agency" \
  -H "Token-Transit-Api-Key: sk_fake_1234567890abcXYZ" \
  -H "Token-Transit-Api-Version: 2019-05-01"

The above command returns JSON structured like this

{
  "agencies": [
    {
      "agency_id": "bigbluebus",
      "agency_name": "Big Blue Bus",
      "location": {
        "latitude": 34.028189,
        "longitude": -118.489176
      },
      "logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
      "region": "Santa Monica, CA",
      "timezone": "America/Los_Angeles",
      "website": "https://www.bigbluebus.com"
    }
  ]
}

GET https://api.tokentransit.com/agency

Optional Headers

Header Default Description
Accept-Language en-US Locale for the user to indicate what language pass information should be returned in. This is only for information that will be shown to the user.

HTTP Response

Field Type Description
agencies Array of Agency objects All of the agencies from which a fare can be purchased.

Fares

A fare corresponds to a specific type of pass that a user can buy through token transit. Each fare has a price, a name, and a description. Fare ids are unique per agency.

Fare object

All endpoints in this section either return an Fare object or a list of Fare objects.

The Fare object response is defined as follows:

Field Name Type When Present Description
agency_id string Always A unique id representing the agency.
agency_name string Always A displayable name for the agency.
alert_text string If additional restrictions apply Additional text to be shown to the user warning about usage restrictions.
description string Always A user-displayable string in the language specified by Accept-Language.
fare_id string Always ID used for the specified fare (same as in the path).
fare_name string Always A displayable name for the fare.
options Array of objects Only from Fare endpoints or if specified with include_fare_options A list of options as described below
options.id string Only from Fare endpoints or if specified with include_fare_options A unique id corresponding to a FareOptionValue
options.type string Only from Fare endpoints or if specified with include_fare_options A unique type corresponding to a FareOption
passes_count number Only if product_type is pass_book Represents the number of passes in the pass book (only populated if the fare respresents purchase of a pass book)
price object Only from Fare endpoints or if specified with include_fare_price (default) An object that contains the price of the fare.
price.amount number Only from Fare endpoints or if specified with include_fare_price (default) An integer specifying the amount of currency in the smallest denomination of the currency.
price.currency string Only from Fare endpoints or if specified with include_fare_price (default) An ISO 4217 three-letter currency code (upper-case).
product_type ProductType enum Always Describes whether the fare is a single_pass or a pass_book. pass_book products result in multiple passes being bought at once and add an additional PassBook object to the returned response.
restricted_purchase boolean Only from Fare endpoints If true, the fare cannot only be purchased by validated users and requires agency approval. See restricted_purchase_text for text to show user.
restricted_purchase_text string Only from Fare endpoints Text to show the user if a fare is restricted.

ProductType is an enum type (represented as a string) that can contain the following values:

Value Meaning
pass_book This fare actually represents a purchase of multiple passes at once and will result in the purchase of a PassBook object.
single_pass This fare represents a purchase of a single pass and will result in the purchase of a Pass object.

Fare Options

Each Fare object will contain a list of option ids. These options help organize the fares into a user-friendly display. Each fare will have a number of options: a rider type, a fare type, and (sometimes) a zone. Although these are the current options that are part of fares, we may add options at any point in the future, and thus listing options is an extensible way to describe the different types.

A FareOption will describe one type of option and all of the available values. Because they are only useful when organizing fares and passes in different ways, the FareOption objects will only be present in API calls that list all fares or passes. In API calls that only return a single Pass or Fare, only the option ids will be included.

A FareOption can be described as follows.

Field Name Type Description
type string A unique id string that may be used programmatically. Some of the existing types are rider, fare, and zone.
label string This is a string label that can be shown to the user next to a selector of a given type.
value Array of FareOptionValue objects A list of all of the values for a particular type of option.

The label should be shown to the user as a label for the category, while the value.name field should be used as the display text to the user and the value.id should be used to uniquely reference the id.

A FareOptionValue object lists the id, user-displayable name, and potentially other information in future versions. The object can be described as follows.

Field Name Type Description
id string A unique id string for the FareOptionValue that may be used programmatically.
name string This is a string that can be shown to the user to represent the values of this type.

When all of the fares are listed, a complete structure of the fares can be obtained broken down into different categories.

The FareOptions are listed in the order that they should be used for selection.

Selecting fare options

In order to display different fare options, FareOptions may be used to break the list of fares into different categories that can be shown to the user. A selector choosing from amongst all the FareOptionValues of the first type should be shown first. Next, the user should select among all of the FareOptionValue in the second category, but only for fares that already match the first category. In the case that a fare does not have a FareOptionValue of a particular type, this selector should be marked as inactive in the UI, as not having a category indicates that the pass cannot be broken down by this particular FareOption.

You can see how passes are selected in the Token Transit to get a feel for how we use the FareOptions in our app.

Retrieving information about a fare

To retrieve information about a type of pass, a request for a Fare object should be made. Generally, it is better to just list all of the fares at once using the list fares endpoint because it also includes the FareOption list.

HTTP Request

curl "https://api.tokentransit.com/agency/bigbluebus/fare/regular_single_ride" \
  -H "Token-Transit-Api-Key: sk_fake_1234567890abcXYZ" \
  -H "Token-Transit-Api-Version: 2019-05-01"

The above command returns JSON structured like this

{
  "agency_id": "bigbluebus",
  "agency_name": "Big Blue Bus",
  "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
  "fare_id": "regular_single_ride",
  "fare_name": "Regular Single Ride",
  "options": [
    {
      "id": "rider_regular",
      "type": "rider"
    },
    {
      "id": "fare_single_ride",
      "type": "fare"
    }
  ],
  "price": {
    "amount": 125,
    "currency": "USD"
  },
  "product_type": "single_pass"
}

GET https://api.tokentransit.com/agency/{agency_id}/fare/{fare_id}

Path components

Path component description
agency_id Unique identifier for the agency.
fare_id Agency-unique identifier for type of pass.

Optional Headers

Header Default Description
Accept-Language en-US Locale for the user to indicate what language pass information should be returned in. This is only for information that will be shown to the user.

HTTP Response

A Fare object with the information about the fare with be returned.

Listing all fares

All fares for a provided agency may be retrieved in a single call.

HTTP Request

curl "https://api.tokentransit.com/agency/bigbluebus/fare" \
  -H "Token-Transit-Api-Key: sk_fake_1234567890abcXYZ" \
  -H "Token-Transit-Api-Version: 2019-05-01"

The above command returns JSON structured like this

{
  "fare_options": [
    {
      "label": "Rider",
      "type": "rider",
      "value": [
        {
          "id": "rider_regular",
          "name": "Regular"
        },
        {
          "id": "rider_reduced",
          "name": "S/D/M"
        }
      ]
    },
    {
      "label": "Fare",
      "type": "fare",
      "value": [
        {
          "id": "fare_single_ride",
          "name": "Single Ride"
        },
        {
          "id": "fare_3_ride",
          "name": "3 Ride"
        }
      ]
    }
  ],
  "fares": [
    {
      "agency_id": "bigbluebus",
      "agency_name": "Big Blue Bus",
      "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
      "fare_id": "regular_single_ride",
      "fare_name": "Regular Single Ride",
      "options": [
        {
          "id": "rider_regular",
          "type": "rider"
        },
        {
          "id": "fare_single_ride",
          "type": "fare"
        }
      ],
      "price": {
        "amount": 125,
        "currency": "USD"
      },
      "product_type": "single_pass"
    },
    {
      "agency_id": "bigbluebus",
      "agency_name": "Big Blue Bus",
      "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
      "fare_id": "reduced_single_ride",
      "fare_name": "S/D/M Single Ride",
      "options": [
        {
          "id": "rider_reduced",
          "type": "rider"
        },
        {
          "id": "fare_single_ride",
          "type": "fare"
        }
      ],
      "price": {
        "amount": 50,
        "currency": "USD"
      },
      "product_type": "single_pass",
      "restricted_purchase": true,
      "restricted_purchase_text": "This pass is restricted. Riders must be pre-authorized by the transit agency to purchase it. For more information, please contact the transit agency."
    },
    {
      "agency_id": "bigbluebus",
      "agency_name": "Big Blue Bus",
      "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
      "fare_id": "regular_3_ride",
      "fare_name": "Regular 3 Ride",
      "options": [
        {
          "id": "rider_regular",
          "type": "rider"
        },
        {
          "id": "fare_3_ride",
          "type": "fare"
        }
      ],
      "passes_count": 3,
      "price": {
        "amount": 350,
        "currency": "USD"
      },
      "product_type": "pass_book"
    },
    {
      "agency_id": "bigbluebus",
      "agency_name": "Big Blue Bus",
      "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
      "fare_id": "reduced_3_ride",
      "fare_name": "S/D/M 3 Ride",
      "options": [
        {
          "id": "rider_reduced",
          "type": "rider"
        },
        {
          "id": "fare_13_ride",
          "type": "fare"
        }
      ],
      "passes_count": 3,
      "price": {
        "amount": 140,
        "currency": "USD"
      },
      "product_type": "pass_book",
      "restricted_purchase": true,
      "restricted_purchase_text": "This pass is restricted. Riders must be pre-authorized by the transit agency to purchase it. For more information, please contact the transit agency."
    }
  ]
}

GET https://api.tokentransit.com/agency/{agency_id}/fare

Path components

Path component description
agency_id Unique identifier for the agency.

Optional Headers

Header Default Description
Accept-Language en-US Locale for the user to indicate what language pass information should be returned in. This is only for information that will be shown to the user.

HTTP Response

Field Type Description
fares Array of Fare objects All of the fares that the user is able to purchase from the agency.
fare_options Array of FareOption objects All of the options that can be used to group fares for displaying to the user.

Passes

Passes are the actual digital product sold by Token Transit. Possession of an active pass shows proof of purchase and can be used to board an appropriate bus for the transit agency. Passes start out as unredeemed and must be redeemed by a user.

Pass Object

All of the endpoints in the the passes section all return a Pass object or a list of Pass and PassBook objects.

The Pass object response is defined as follows:

Field Type Description
agency_id string String that indicates the ID of the agency the pass is for
details object Object including details of the pass. This should always be used over fare field because some passes do not have a fare field.
details.alert_text string If populated, information that the user should be made aware of before activating the pass. This is typically a description of a usage restriction.
details.alert_label string If populated, a brief description or label for the contents of alert_text that should be prominently displayed when the pass is active. (Note that alert_label might be absent even if alert_text is present.)
details.agency_name string Name of the agency that the pass belongs to.
details.description string Description of the pass to show to the user.
details.name string Name of the pass to show to the user.
fare Fare object A Fare object containing the fare details (may only have the fare_id and fare_name fields populated). This field is not always populated in the response, specifically for passes that are part of pass books.
logo_url string Logo to show for this pass if present. This may be different than the agency logo shown for agency selection. If field is not present then the logo_url from the Agency object should be used instead. Caching the logo is recommened.
pass_id string A unique ID for the pass.
pass_book_id string If populated, the pass book that this pass belongs to. Passes from the same book should be visually grouped together unless they are active.
pass_transfer_id string The id of a pass transfer that this object belongs to.
payment_processor string The payment processor used for payment.
purchase_timestamp Date (RFC 3339) A timestamp indicating when a pass was purchased.
refund_timestamp Date (RFC 3339) A timestamp indicating when a pass was refunded (only shown if pass is not part of a pass book)
transfer_timestamp Date (RFC 3339) A timestamp indicating when a pass was transferred
status PassStatus enum A string code that indicates the status of the pass.
valid_time_ranges Array of TimeRange objects If this field is present, it indicates that the pass is only usable within a certain set of time ranges. If the current time is not within one of the given TimeRanges, the pass cannot be activated.

Pass Statuses

A pass may have a number of statuses. These statuses indicate the state of a pass and whether the pass is usable for boarding, can be activated, and is valid for later use.

Status Meaning
activated_after_transfer Pass has been transferred and it was activated after transfer.
awaiting_transfer Pass has been purchased but not yet redeemed by user.
invalid Pass can no longer be transferred.
refunded Pass has been refunded and may no longer be redeemed.
transferred Pass has been claimed and transferred to a user.
unactivated Pass has been purchased but is not actually part of a transfer.

PassBook Object

Pass books are a sets of passes that can be used individually but are purchased as one item.

The PassBook object is defined as follows:

Field Type Description
fare Fare object A Fare object containing the fare details (may only have the fare_id and fare_name fields populated).
logo_url string Logo to show for this pass_book if present. This may be different than the agency logo shown for agency selection. If field is not present then the logo_url from the Agency object should be used instead.
payment_processor string The payment processer used to purchase this pass book.
pass_book_id string A unique id for the pass book. Future endpoints may support direct lookup of pass book details. This id is also used to group together passes from the same book.
pass_transfer_id string The id of a pass transfer that this object belongs to.
purchase_timestamp Date (RFC 3339) A timestamp indicating when a pass book was purchased.
refund_timestamp Date (RFC 3339) A timestamp indicating when a pass book was refunded.
transfer_timestamp Date (RFC 3339) A timestamp indicating when a pass book was transferred/redeemed.
unactivated_remaining_count number The number of passes left in the book that can still be activated. This may be helpful to show to the user.

PassTransfer Object

Pass transfers correspond to the transfer of a pass from one account to another (usually from your administrative account to a new account).

The PassTransfer object is defined as follows:

Field Type Description
authorized_user_id string An id corresponding to the authorized user of the passes.
creation_timestamp Date (RFC 3339) A timestamp indicating when a pass book w
destination_user_id string An id corresponding to the user that redeemed the transfer.
id string An ID corresponding to the transfer itself. These can be refunded.
items array of PassTransferItems Items that are in this transfer.
metadata object Key/values that were passed in at time of purchase.
redemption object Information about redeeming the pass.
redemption.url string Send this to a user to allow them to redeem a pass.
redemption.expiration_timestamp Date (RFC 3339) The expiration timestamp of the redemption link. If the transfer has not been completed by this time, then the items in the transfer are automatically refunded. If this field is missing, there is no expiration.
status enum A field with value awaiting_transfer, transferred, activated_after_transfer, refunded, partially_refunded, or cancelled indicating the status of the transfer. A transfer can only have the cancelled status if it was never redeemed.
refund_timestamp Date (RFC 3339) A timestamp indicating when the transfer was refunded or cancelled.
transfer_timestamp Date (RFC 3339) A timestamp indicating when the transfer was completed.

PassTransferItem Object

A PassTransferItem corresponds to either a Pass or PassBook that is an item in the user's account.

The PassTransferItem object is defined as follows:

Field Type Description
activation_timestamp Date (RFC 3339) Date of activation of the item. If an item is activated, it cannot be refunded.
fare Fare object A Fare object containing the fare details (may only have the fare_id and fare_name fields populated).
pass_id string The id of the object that will be transferred. If both pass_id and pass_book_id fields are missing then the pass will be purchased on redemption. Otherwise this id will refer to a pass in the passes response.
pass_book_id string The id of the object that will be transferred. If both pass_id and pass_book_id fields are missing then the pass will be purchased on redemption. Otherwise this id will refer to a pass in the pass_books response.
purchase_timestamp Date (RFC 3339) Date of purchase of the item.
refund_timestamp Date (RFC 3339) Date of refund of the item. If pass transfer state is cancelled, this won't be
type enum Either pass, pass_book, or purchase_on_redemption indicating what kind of item this is. If the item is purchase_on_redemption, there will be no id for the pass.

Purchasing fares for redemption (User Authentication Required)

To purchase passes or pass bookes for a user to redeem, a POST request supplying a valid fare_ids[] and agency id (via the a param) should be sent to the pass purchase endpoint.

HTTP Request

curl -X POST \
  -H "Token-Transit-Api-Key: sk_fake_1234567890admin1" \
  -H "Token-Transit-Api-Version: 2019-05-01" \
  -d a=bigbluebus \
  -d fare_ids[]=regular_single_ride \
  -b /tmp/tt_fake_api_cookies \
  -c /tmp/tt_fake_api_cookies \
  "https://api.tokentransit.com/purchase/bulk"

The above command returns JSON structured like this:

{
  "pass_books": null,
  "passes": [
    {
      "agency_id": "bigbluebus",
      "details": {
        "agency_name": "Big Blue Bus",
        "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
        "name": "Regular Single Ride"
      },
      "fare": {
        "agency_id": "bigbluebus",
        "agency_name": "Big Blue Bus",
        "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
        "fare_id": "regular_single_ride",
        "fare_name": "Regular Single Ride",
        "price": {
          "amount": 100,
          "currency": "USD"
        }
        "product_type": "single_pass",
      },
      "pass_id": "pass_unactivated",
      "payment_processor": "Stripe",
      "purchase_timestamp": "2020-03-13T16:39:29.988256565-07:00",
      "status": "awaiting_transfer",
    }
  ],
  "pass_transfers": [
    {
      "id": "ptfr_1234567890abcXYZ",
      "items": [{
        "fare": {
          "agency_id": "bigbluebus",
          "agency_name": "Big Blue Bus",
          "fare_id": "regular_single_ride",
          "fare_name": "Regular Single Ride",
          "product_type": "single_pass"
        },
        "id": "pass_unactivated",
        "purchase_timestamp": "2020-03-13T16:39:29.988256565-07:00",
        "status": "awaiting_transfer",
      }],
      "redemption": {
        "url": "https://app.tokentransit.com/redeem/rdm_1234567890abcXYZ",
      },
      "metadata": {
        "invoice_id": 123,
      },
      "status": "awaiting_transfer",
    }
  ],
}

POST https://api.tokentransit.com/purchase/bulk

Query Parameters

Parameter Required/Default Description
a Required The agency_id of the agency to purchase the fare from.
fare_ids[] Required The IDs of the fares to be purchased. The same id may be specified multiple times. To add multiple fares, specify the fare_ids[] parameter multiple times. Each specification should include a single fare id.
metadata missing A dictionary of extra pieces of information to record. This can be useful for recording extra information along with the purchase. These should be specified in standard query parameter key/value format metadata[key]=value. metadata parameter may be specified multiple times.

HTTP Response

Field Type Description
passes Array of Pass objects All of the passes that have been purchased.
pass_books Array of PassBook objects All of the pass books that have been purchased.
pass_transfers Array of PassTransfer objects All of the pass transfers that are related to the purchase.

Listing all passes and pass transfers (User Authentication Required)

Existing passes and pass transfers may be retrieved for a user. omit_unusable_passes may not be set to false unless pass_transfer_id is specified. If pass_transfer_id is specified, then only passes related to the specified id will be returned.

HTTP Request

curl "https://api.tokentransit.com/pass?omit_unsuable_passes=false&pass_transfer_id=ptfr_1234567890abcXYZ" \
  -H "Token-Transit-Api-Key: sk_fake_1234567890admin1" \
  -H "Token-Transit-Api-Version: 2020-05-21"

The above command returns JSON structured like this:

{
  "pass_books": null,
  "passes": [
    {
      "agency_id": "bigbluebus",
      "details": {
        "agency_name": "Big Blue Bus",
        "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
        "name": "Regular Single Ride"
      },
      "fare": {
        "agency_id": "bigbluebus",
        "agency_name": "Big Blue Bus",
        "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
        "fare_id": "regular_single_ride",
        "fare_name": "Regular Single Ride",
        "product_type": "single_pass"
      },
      "pass_id": "pass_unactivated",
      "payment_processor": "Stripe",
      "purchase_timestamp": "2020-03-13T16:39:29.988256565-07:00",
      "status": "awaiting_transfer"
    }
  ],
  "pass_transfers": [
    {
      "id": "ptfr_1234567890abcXYZ",
      "items": [
        {
          "fare": {
            "agency_id": "bigbluebus",
            "agency_name": "Big Blue Bus",
            "fare_id": "regular_single_ride",
            "fare_name": "Regular Single Ride",
            "product_type": "single_pass"
          },
          "id": "pass_unactivated",
          "purchase_timestamp": "2020-03-13T16:39:29.988256565-07:00",
          "status": "awaiting_transfer",
          "type": "pass"
        }
      ],
      "redemption": {
        "url": "https://app.tokentransit.com/redeem/rdm_1234567890abcXYZ"
      },
      "metadata": {
        "invoice_id": 123
      },
      "status": "awaiting_transfer"
    }
  ]
}

GET https://api.tokentransit.com/pass

Query Parameters

Parameter Required/Default Description
omit_unusable_passes true If true, only returns passes that have not yet been transferred.
pass_transfer_id "" If specified, only the passes associated with the pass transfer will be returned

HTTP Response

Field Type Description
passes Array of Pass objects All of the passes that have been purchased.
pass_books Array of PassBook objects All of the pass books that have been purchased.
pass_transfers Array of PassTransfer objects All of the pass transfers that are available.

Refunding a Pass, Pass Book, or Pass Transfer

As long as a pass or pass book has not been transferred and activated, it may refunded. Pass transfers may be refunded as well.

Semantics for refunding pass transfers:

Status Effect
awaiting_transfer Transfer will be cancelled and all passes and pass books refunded.
transferred All passes in the transfer will be refunded.
activated_after_transfer Error pass_activated
partially_refunded Error pass_refunded
refunded No op
cancelled No op

Semantics for refunding individual passes or pass books:

Status Effect
awaiting_transfer Transfer that pass or pass book is part of will be cancelled and all passes and pass books in the transfer refunded
transferred Specified pass or pass book will be refunded
activated_after_transfer Error pass_activated
refunded No op

HTTP Request

curl -X POST \
  -H "Token-Transit-Api-Key: sk_fake_1234567890admin1" \
  -H "Token-Transit-Api-Version: 2019-05-01" \
  -d id="pass_unactivated" \
  -b /tmp/tt_fake_api_cookies \
  -c /tmp/tt_fake_api_cookies \
  "https://api.tokentransit.com/refund"

The above command returns JSON structured like this:

{
  "pass_books": null,
  "passes": [
    {
      "agency_id": "bigbluebus",
      "details": {
        "agency_name": "Big Blue Bus",
        "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
        "name": "Regular Single Ride",
        "type": "pass"
      },
      "fare": {
        "agency_id": "bigbluebus",
        "agency_name": "Big Blue Bus",
        "description": "Valid on all local Big Blue Bus routes. Single ride is valid for 30 minutes after use.",
        "fare_id": "regular_single_ride",
        "fare_name": "Regular Single Ride",
        "product_type": "single_pass"
      },
      "pass_id": "pass_unactivated",
      "payment_processor": "Stripe",
      "purchase_timestamp": "2020-03-13T16:39:29.988256565-07:00",
      "refund_timestamp": "2020-03-13T16:39:29.988256565-07:00",
      "status": "refunded"
    }
  ],
  "pass_transfers": [
    {
      "id": "ptfr_1234567890abcXYZ",
      "creation_timestatmp": "2020-03-13T16:39:29.988256565-07:00",
      "items": [
        {
          "fare": {
            "agency_id": "bigbluebus",
            "agency_name": "Big Blue Bus",
            "fare_id": "regular_single_ride",
            "fare_name": "Regular Single Ride",
            "product_type": "single_pass"
          },
          "id": "pass_unactivated",
          "type": "pass",
          "purchase_timestamp": "2020-03-13T16:39:29.988256565-07:00",
          "refund_timestamp": "2020-03-13T16:39:29.988256565-07:00"
        }
      ],
      "metadata": {
        "invoice_id": 123
      },
      "refund_timestamp": "2020-03-13T16:39:29.988256565-07:00",
      "status": "cancelled"
    }
  ]
}

POST https://api.tokentransit.com/refund

Query Parameters

Parameter Required/Default Description
pass_id Conditionally Required Refunds the specified pass
pass_book_id Conditionally Required Refunds the specified pass book
pass_transfer_id Conditionally Required Refunds the specified pass book

Headers

The following headers are either required, strongly recommended, or specific to this endpoint.

Name Required Description
Idempotency-Key Strongly Recommended A key to unique to the given request. Specifying an idempotency key will guarantee a single purchase per key no matter how many times the endpoint is called.

HTTP Response

Field Type Description
passes Array of Pass objects All of the passes that were related to the refund
pass_books Array of PassBook objects All of the pass books that were related to the refund
pass_transfers Array of PassTransfer objects All of the pass transfers that were related to the refund