Introduction
Welcome to the Token Transit Ticketing API.
The Token Transit Ticketing API is a RESTful service that can be used to purchase transit passes on behalf of an authenticated users in third-party applications and display the resulting tickets for transit agencies that Token Transit works with. 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.
Versions
The current version of the Token Transit API is 2020-05-21
. The API version is updated when there are breaking changes to the API. These changes are recorded below.
Changes in Token Transit API versions:
Version | Changes |
---|---|
2020-05-21 |
Fare Free improvements to the API. The Agency object now includes service_alerts and the /agency/{agency_id}/fare endpoint will return an empty list of fares if the agency is currently fare free and fares cannot be purchased. |
2019-05-01 |
Initial release of the Token Transit API. |
Headers
The Token Transit Ticketing 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.
Cookies used are described in the Cookies section.
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 |
Token-Transit-Passes-State |
Purchase and Activate (but safe to add to any call) | N/A (Required on Purchase or Activate) | Tells the server only to perform the action if the client account state is up to date. This is required for purchase endpoint /purchase and always required for the activate endpoint /pass/{pass_id}/activate . You should read this header from calls to purchase, activate, or list passes and send it back in the purchase and activate calls. |
Accept-Language |
Fares, Agencies | en-US |
User language for requesting results in a different language |
Authentication |
All Pass Enpoints, Login | N/A (Ignored/optional if user_session_id cookie is provided) |
A JWT signed by your service authenticating the user |
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. |
Token-Transit-Passes-State |
Purchase, Activate, List Passes endpoints | The latest version of user pass state. This should always be sent back to the server using the same Token-Transit-Passes-State header on purchase and activate endpoints. It can always be fetched by calling the list passes endpoint. |
Cookies
These are all of the cookies that are used in the API.
Cookie Name | Endpoints | Description |
---|---|---|
user_session_id |
Purchase, Pass Retrieval, Login, Logout | A session id that can be used instead of a JWT to authenticate a user. |
API Authentication
Token Transit Ticketing API uses API keys for authentication of your service. If you are integrating with us, your publishable and secret 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 a 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 must have 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:
- JSON Web Token (JWT) IETF RFC 7519: JWTs are a standardized way of sending publicly verififiable user tokens securely to Token Transit so that we can accept your user credentials in our app.
- JSON Web Key (JWK) IETF RFC 7517: JWKs are a standardized way of providing the public key component of a public/private key pair used to sign your JWTs.
- JSON Web Algorithms (JWA) IETF RFC 7518: JWAs are a set of predetermined secure algorithms for public/private key signing. Token Transit expects either RSA (RS256, RS384, or RS512) or EC (ES256, ES384, ES512) to be used as algorithms for your JWK and JWT. If you are unsure of what option to choose when setting up your service, RS256 is widely supported and will work well with Token Transit.
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 your user that must be unique and that you can use to look up the 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 |
Required | Specifies a contact method for the user. We require an email contact method for customer service purposes and to send users receipts. |
device_id |
Conditionally Required | If you will be generating and showing our visual tickets in your app, then you must provide a unique ID that represents a user's device. Some contracts with agencies require us to prevent users from sharing tickets across devices. |
phone_number |
Optional | Specifies a sms contact method for the user. We may use phone number to communicate notifications to a user. (We also accept phone as an alias for this claim name.) |
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.
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
.
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. |
412 | Precondition Failed | Account state is out of date. You must refresh passes on the account and send back Token-Transit-Passes-State header in the new request. |
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 suitable for displaying to the end user (localized). |
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) |
---|---|---|---|
account_state_out_of_sync |
Changes to user's account have occurred since pass list was last fetched | Fetch user's passes with /pass and show them to user. Send back Token-Transit-Passes-State header in next request. |
false |
activated_pass_already_on_device |
User tries to purchase 2nd pass while 1st pass is currently active /agency/{agency_id}/fare/{fare_id}/purchase only) |
Display error | false |
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 |
existing_purchase_in_progess |
Another purchase is already in progress on this account. Purchase will be blocked for at most 2 minutes | Display error and prompt user to retry in at most 2 minutes | false |
fares_cannot_be_purchased |
User not allowed to purchase fare on this platform | Send back cart to refresh fares and repopulate list of fares | false |
fares_out_of_date |
Agency fares have been updated | Re-fetch agency fares and begin purchase flow again | false |
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 |
invalid_email_address |
User entered an e-mail address that was not parseable | Indicates that not enough validation was done for user email addresses. This error should not occur for properly formatted e-mail addresses | false |
invalid_cart |
The requested collection of passes is not valid (for example, because a quantity limit is exceeded) | Display the error and continue from the last valid cart. | false |
invalid_id |
An endpoint was called with an incompatible ID (e.g. /pass/{pass_id} was called with a pass book id) |
Fix internal code to only pass in proper IDs to endpoints. | false |
login_required |
An action was attempted that requires authentication | Provide user authentication when attempting the request again | 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_active_on_another_device |
User tried to activate a pass that is already in use on another device | Display error. User may use pass again on the next day if it is still valid | false |
pass_cannot_be_activated_at_this_time |
User tried to activate a pass outside of its activation window | Display error to user. You may want to check activation windows and display information to user instead of hitting the activation endpoint. | false |
pass_expired |
User tried to activate a pass that is expired | Error should not be encountered if properly monitoring pass expiration. If encountered, display error and refresh user passes | false |
pass_invalid |
User tried to activate a pass that was invalidated by Token Transit | Display error and refresh user passes | false |
pass_refunded |
User tried to activate a pass that has been refunded | Display error and refresh user passes | false |
passes_state_header_invalid_or_missing |
An endpoint was called that requires the Token-Transit-Passes-State header |
Fetch user's passes with /pass and show them to user. Send back Token-Transit-Passes-State header in next request. |
false |
pass_transferred |
User tried to activate a pass that was transferred | Optionally show user the error. This indicates that you have a bug in your pass listing logic. Passes that are transferred should not be displayed |
false |
pass_transfer_in_progress |
User tried to activate a pass that is in the process of being transferred | Show user the error. This may indicate that you have a bug in your pass listing logic as you shouldn't normally be able to hit this endpoint without an account sync error. Passes that are awaiting_transfer should not be displayed |
false |
pass_transfer_into_source_account |
User is attempting to redeem a pass or passes that are coming from their own account | Show user the error. | false |
pass_unactivated |
Attempted to make visual validation call with an unactivated pass | Do not show error to user. This indicates a bug in your visual validation logic. | false |
payment_method_not_found |
Purchase attempted without payment method | Indicates a bug in your purchase logic. Probably show user this message, and ensure purchase never happens without a payment method. Rotate idempotency key before retrying | false |
redemption_already_used |
User attempted to redeem something that was already redeemed by the same account | Show the error to the user and then refresh passes. | false |
redemption_invalid |
Either a user specified an invalid redemption code, the redemption link is expired, or there's a bug in the redemption logic | Show the error to the user. | false |
redemption_ineligible |
User tried to a redeem something that their account is not eligible to redeem | Show the error to the user. | false |
redemption_limits_exceeded |
User attempted to redeem something that has per-account limits and they already redeemed too many similar items | Show the error to the user | false |
redemption_used_by_another_account |
User tried to redeem something but it had already been claimed by another account | Show the error to the user. | false |
restricted_purchase |
User cannot purchase pass due to purchase restrictions | Display error and information about purchase restrictions. Users should be barred from attempting purchase of restricted passes. | 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 |
single_order_pass_limit_exceeded |
Too many passes added to the cart | Show the user the error message and then show the cart contents | false |
stale_cart |
A purchase was attempted with an out-of-date cart | The cart must be refreshed via a /cart POST request with the cart_token . |
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",
"stripe_publishable_api_key": "pk_test_1234567890abcXYZ",
"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 |
stripe_publishable_api_key |
string | A Stripe publishable API key to use with Stripe API requests |
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" \
-d include_stripe_customer_id=true \
-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
{
"stripe_customer_id": "cus_1234567890abdXYZ"
}
POST https://api.tokentransit.com/user/login
Query Parameters
Parameter | Required/Default | Description |
---|---|---|
include_stripe_customer_id (Secret Key Only) |
false |
If true , return the Stripe customer id, but only if using a secret API key. |
accepted_latest_terms |
false |
If true , acknowledges that the user was shown the Token Transit terms of service and privacy policy and has accepted the latest terms. |
HTTP Response
Field Name | Type | Description |
---|---|---|
stripe_customer_id |
string |
The Stripe customer id of the user (for use with attaching a source to a customer. This will only be returned if include_stripe_customer_id is set to true |
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.
Retrieve a Stripe ephemeral key (User Authentication Required)
To retrieve a Stripe ephemeral key for the current user, make a POST request to the stripe_ephemeral_key
user endpoint. See the client-side Stripe documentation for iOS and Android on how to consume this ephemeral key in a client-side mobile application.
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" \
-d stripe_api_version=2019-12-03 \
-b /tmp/tt_fake_api_cookies \
-c /tmp/tt_fake_api_cookies \
-X POST \
"https://api.tokentransit.com/user/stripe_ephemeral_key"
The above command returns JSON with unspecified internal structure that should be returned as is to Stripe for use with Stripe endpoints that require an ephemeral key.
{
"internal": "fields"
}
POST https://api.tokentransit.com/user/stripe_ephemeral_key
Parameters
Name | Required | Description |
---|---|---|
stripe_api_version |
true |
The Stripe API version used by the client-side mobile application. |
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 be JSON with unspecified internal structure that should be returned as is to Stripe for use with Stripe endpoints that require an ephemeral key. Do not depend on the internal fields specified in the JSON response. Ensure that client-side code passes this JSON response unmodified to Stripe APIs.
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. |
country |
string |
An ISO 3166-1 alpha-2 2-letter country code of the country or region where this agency operates. |
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 ServiceAlert objects. |
ServiceAlert object
A Service Alert is an alert that should be displayed to the user when that tells them timely alerts about the agency.
Field | Type | Description |
---|---|---|
header |
string |
Header for the alert in an Array object. |
description |
string |
Description for the alert in an Array object. |
effect |
ServiceAlertEffect enum |
Effect for the alert in an Array object. |
ServiceAlert 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: 2020-05-21"
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: 2020-05-21"
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.
Price object
Fares may contain Price
objects. The Price
object is defined as follows:
Field Name | Type | Description |
---|---|---|
price.amount |
number |
An integer specifying the amount of currency in the smallest denomination of the currency. |
price.currency |
string |
An ISO 4217 three-letter currency code (upper-case). |
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. |
purchase_alert_text |
string |
If relevant | Information that the user should be made aware of before purchasing a fare. If the alert_text for options is not displayed during fare selection, show alert_text instead. |
alert_text |
string |
If relevant | Information that the user should be made aware of before purchasing a fare. If the alert_text for options is displayed during fare selection, show purchase_alert_text instead. |
alert_label |
string |
If relevant | A brief description or label for the contents of alert_text . (Note that alert_label might be absent even if alert_text is present.) |
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 object s |
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) |
A Price object that contains the usual price of the fare. |
discounted_price |
object |
Only from Fare endpoints or if specified with include_fare_price (default), when a discount applies |
A Price object that contains the discounted price of the fare. Discounts will only be applied to purchases made via Cart . |
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 be purchased by the user and requires agency approval. See restricted_purchase_text for text to show user. |
restricted_purchase_label |
string |
Only from Fare endpoints |
Text to show show as a header if fare is restricted. This text may also be used alongside the earliest option in the tree that has no children that are not restricted |
restricted_purchase_text |
string |
Only from Fare endpoints |
Text to show the user if a fare is restricted. |
login_required |
boolean |
If relevant | If true, indicates that user authentication is required in order to add the fare to a cart. |
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. |
description |
string |
If populated, a description of the option. |
alert_text |
string |
If populated, information that the user should be made aware of before when selecting a fare with this option. This is typically a description of a usage restriction. |
alert_label |
string |
If populated, a brief description or label for the contents of alert_text that should be prominently displayed when selecting this option. (Note that alert_label might be absent even if alert_text is present.) |
When all of the fares are listed, a complete structure of the fares can be obtained broken down into different categories.
The FareOption
s are listed in the order that they should be used for selection.
Selecting fare options
In order to display different fare options, FareOption
s 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 FareOptionValue
s 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 FareOption
s 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: 2020-05-21"
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: 2020-05-21"
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.",
"restricted_purchase_label": "Restricted"
},
{
"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.",
"restricted_purchase_label": "Restricted"
}
]
}
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. |
Carts
A cart is a collection of fares to be purchased, and includes information about the prices of the selected fares. Carts are populated using the /cart
endpoint, and a cart can be provided to the /purchase
endpoint to purchase the selected fares.
Cart Object
The Cart
object is defined as follows:
Field | Type | Description |
---|---|---|
cart_token |
string |
Opaque string that identifies the contents of the cart. |
agency_id |
string |
ID of the agency the user is shopping. |
country |
string |
An ISO 3166-1 alpha-2 2-letter country code of the country or region where this agency operates. |
items |
Array of CartItem objects |
The contents of the cart. |
total_price |
Price object |
The total price of the cart, before any discounts. |
discounted_total_price |
Price object |
If discounts apply, the total price of the cart including discounts. |
agency_fares |
Array of Fare objects |
All of the fares that the user is able to purchase from the agency. |
agency_fare_options |
Array of FareOption objects |
All of the options that can be used to group fares for displaying to the user. |
purchase_alert_text |
string |
Information that the user should be made aware of before purchasing the cart. |
alert_labels |
Array of string s |
Brief warning text that should be displayed before purchasing the cart. |
service_alerts |
Array of ServiceAlert objects |
An array of ServiceAlert objects that inform the user about any timely information about this cart. |
CartItem Object
The CartItem
object contains:
Field | Type | Description |
---|---|---|
fare |
Fare object |
A fare that is in the cart. |
quantity |
number |
The number of the fare in the cart. |
total_fare_price |
Price object |
The total price for this CartItem , before any discounts. |
discounted_total_fare_price |
Price object |
If discounts apply, the total price for this CartItem including discounts. |
Populating a cart
To populate a cart, a POST
reqest should be sent to the cart endpoint. Provide either cart_token
to base your cart on an existing cart or a
(agency ID) to start from a new, empty cart. add_fares
, update_fares
, and remove_fares
may all be provided, but any individual fare ID may only appear in one of them.
HTTP Request
The following command assumes you have already sent a login request and saved cookies in
/tmp/tt_fake_api_cookies
curl -X POST \
-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 \
-H "Content-Type: application/json" \
-d 'a=bigbluebus' \
-d 'add_fares[regular_single_ride]=2' \
"https://api.tokentransit.com/cart"
The above command returns JSON structured like this:
{
"cart_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJ0djEiOnsiYWduIjoiYWhSemZuUnZhMlZ1TFhSeVlXNXphWFF0ZEdWemRISVRDeElHUVdkbGJtTjVHSUNBZ0lENHdvUUtES0lCQkhSbGMzUSIsImZzIjoiYWhSemZuUnZhMlZ1TFhSeVlXNXphWFF0ZEdWemRISXRDeElHUVdkbGJtTjVHSUNBZ0lENHdvUUtEQXNTRFVaaGNtVlRkSEoxWTNSMWNtVVlnSUNBZ0lDQWdBb01vZ0VFZEdWemRBIiwiaXRlbXMiOlt7ImZhcmVfaWQiOiJmdWxsX2ZhcmVfMV9yaWRlIiwicXVhbnRpdHkiOjR9XSwiUHJpY2UiOnsiYW1vdW50IjoxNzUsImN1cnJlbmN5IjoiVVNEIn19fQ.4onJHS-CyZw_8xgWVrsvs2LnmX97ErHKEIkj2jwTrbs",
"agency_id": "bigbluebus",
"items": [
{
"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",
"options": [
{
"id": "rider_regular",
"type": "rider"
},
{
"id": "fare_single_ride",
"type": "fare"
}
],
"price": {
"amount": 125,
"currency": "USD"
},
"product_type": "single_pass"
},
"quantity": 2,
"total_fare_price": {
"amount": 250,
"currency": "USD"
}
}
],
"total_price": {
"amount": 250,
"currency": "USD"
},
"agency_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.",
"restricted_purchase_label": "Restricted"
}
],
"agency_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"
}
]
}
]
}
POST https://api.tokentransit.com/cart
Parameters
Field | Type | Required/Default | Description |
---|---|---|---|
cart_token |
string |
Optional | Provide a cart_token to create a Cart based on a previous Cart . |
a |
string |
Optional | Provide an agency ID to create a new Cart from empty. (If cart_token is provided, a must not be provided.) |
add_fares |
Key-value map of Fare IDs to quantities | Optional | Add the fares in the given quantities. |
update_fares |
Key-value map of Fare IDs to quantities | Optional | Set the quantities for the given fares. |
remove_fares |
Key-value map of Fare IDs to quantities | Optional | Decrease the fares in the cart by the given quantities. |
A request must specify either a
or cart_token
.
HTTP Response
A cart
object is returned.
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.
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. |
display_html |
string |
Base64-encoded or raw HTML ticket that should be displayed to the user in a web view. This will be omitted from the response if your platform is not allowed to show tickets for this agency. |
end_timestamp |
Date (RFC 3339) |
A timestamp indicating when the pass expires; or, if unactivated, a time based on the time of the API request (see note). |
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. |
payment_processor |
string |
The payment processor used for payment. |
purchase_receipt |
Receipt |
Object with details about a purchase receipt for the Pass (if available). This field may not be present if pass is part of a pass book or if user did not purchase the pass in the app. |
purchase_timestamp |
Date (RFC 3339) |
A timestamp indicating when a pass was purchased. |
refund_receipt |
Receipt |
Object with details about a refund receipt for the Pass (if available). This field will only be present if the pass is refunded and may not be present if the pass is part of a pass book or if the user did not purchase the pass in the app. |
refund_timestamp |
Date (RFC 3339) |
A timestamp indicating when a pass was refunded. |
start_timestamp |
Date (RFC 3339) |
A timestamp indicating when the pass was first activated; or, if unactivated, the time of the API request (see note). |
status |
PassStatus enum |
A string code that indicates the status of the pass. |
stripe_source |
string |
Only displayed for passes that were bought as part of a purchase on the purchase call. |
ticket_expiration_timestamp |
Date (RFC 3339) |
A timestamp indicating when a pass must next be activated. This also indicates when a cached pass must be refreshed. |
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 | Usable for boarding | Able to be activated | Valid for future rides |
---|---|---|---|---|
unactivated |
Pass has not yet been activated | false |
true |
true |
active |
Pass is already active on this device | true |
true |
true |
stale_ticket |
Pass has been activated before but must be activated again |
false |
true |
true |
active_on_another_device |
Pass has been activated on another device and cannot be used on this device until the next day | false |
false |
true |
expired |
Pass has expired and may no longer be used | false |
false |
false |
refunded |
Pass has been refunded and may no longer be used | false |
false |
false |
invalid |
Pass has been invalidated and may no longer be used | false |
false |
false |
fare_capped |
Pass has been upgraded via fare capping and may no longer be used | false |
false |
false |
Passes that span multiple days will be reset to stale_ticket
at the end of each day. To determine the time that this status will go into effect, use the ticket_expiration_timestamp
. After this time, a pass must be reactivated
to be usable again. Passes may be reactivated automatically, but keep in mind that as soon as a pass is reactivated it will be "pinned" to the device that activates it for the rest of the day. For this reason, you may want to prompt the user before reactivating passes.
TimeRange object
This object represents an interval of time, possibly unbounded on one end.
The TimeRange
object is defined as follows:
Field | Type | Description |
---|---|---|
start_timestamp |
Date (RFC 3339) |
A timestamp indicating the start of the time range. If not populated, the time range has no start (i.e. it extends forever into the past). |
end_timestamp |
Date (RFC 3339) |
A timestamp indicating the end of the time range. If not populated, the time range has no end (i.e. it extends forever into the future). |
Receipt object
This object represents information about a receipt (either purchase or refund).
The Receipt
object is defined as follows:
Field | Type | Description |
---|---|---|
link |
string |
A URL permalink to the receipt |
number |
string |
A short string that can be displayed to the user. Prepending this string with # is acceptable but not required |
PassBook Object
Pass books are a set of passes that can be used individually but are purchased as one item. Pass books have their own ID which should be used to group together passes that are part of one book in the UI. One way to do this is to show information from the pass book instead until passes are activated and then individually show the activated passes. Pass books also have additional fields to indicate the number of passes remaining in the book.
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. |
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. Caching the logo is recommened. |
pass_transfer_id |
string |
An id indicating that the pass is part of a pass transfer. |
payment_processor |
string |
The |
purchase_receipt |
Receipt |
Object with details about a purchase receipt for the PassBook (if available). This field may not be present if the pass book was not purchased by the user in the app. |
purchase_timestamp |
Date (RFC 3339) |
A timestamp indicating when a pass book was purchased. |
refund_receipt |
Receipt |
Object with details about a refund receipt for the PassBook (if available). This field will not be present if the pass book is not refunded and may not be present if the user did not purchase the pass book in the app. |
refund_timestamp |
Date (RFC 3339) |
A timestamp indicating when a pass book was refunded. |
stripe_source |
string |
A reusabled Stripe ID. It is only displayed for pass books that were bought as part of a purchase on the purchase call. |
transfer_timestamp |
string |
A timestamp indicating when a transfer was transferred. |
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. This will always be 0 if the pass book can't be used (i.e. if it was transferred) |
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 |
---|---|---|
creation_timestamp |
Date (RFC 3339) |
A timestamp indicating when a pass book w |
id |
string |
An ID corresponding to the transfer itself. These can be refunded. |
items |
array of PassTransferItem |
Items that are in this transfer. |
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 , 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 |
---|---|---|
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 pass object that will be transferred. |
pass_book_id |
string |
The id of the pass book object that will be transferred. |
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 or pass_book depending on item type transferred. |
Purchasing a pass (User Authentication Required)
To purchase a pass, make a POST
request to the /purchase
endpoint. This request should specify the fares to be purchased by providing either a cart_token
or the combination of an agency id (via the a
param) and fare_id
.
HTTP Request
The following command assumes you have already sent a login request and saved cookies in
/tmp/tt_fake_api_cookies
curl -X POST \
-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 \
-d a=bigbluebus \
-d fare_id=regular_single_ride \
-d include_fare_price=false \
-d stripe_token=card_1234567890abcXYZ \
-d ticket_format=none \
"https://api.tokentransit.com/purchase"
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"
},
"end_timestamp": "2020-03-14T18:39:29.988256565-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_unactivated",
"payment_processor": "Stripe",
"purchase_timestamp": "2020-03-13T16:39:29.988256565-07:00",
"start_timestamp": "2020-03-14T16:39:29.988256565-07:00",
"status": "unactivated",
"stripe_source": "card_1234567890abcXYZ"
}
]
}
The result contains all passes and their statuses in the account. The
user_token
in the command may be pasted into jwt.io.
POST https://api.tokentransit.com/purchase
Query Parameters
Parameter | Required/Default | Description |
---|---|---|
a |
Optional | The agency_id of the agency to purchase the fare from. |
fare_id |
Optional | The ID of the fare to be purchased. |
cart_token |
Optional | The cart to be purchased. |
stripe_token |
Required | A Stripe token (begins with tok_ ), source (begins with card_ ), or payment method (begins with pm_ ) corresponding to a user-supplied credit or debit card that Token Transit can use to charge a user for the purchase. |
ticket_format |
Required | html_base64 returns a ticket in base64-encoded HTML, html_raw returns a ticket with HTML simply with JSON string escaping, none omits the ticket_html field. |
include_fare_options |
false |
If true, includes fare option info for each pass as well as a fare_options object. |
include_fare_price |
true |
If true, includes price of fare at the time of purchase. |
omit_unusable_passes |
true |
If true, only returns passes that might be usable by the user. |
Either fare_id
or cart_token
must be supplied.
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. |
Token-Transit-Passes-State |
Required | This header specifies the state of the account as it was last shown to the user. You can fetch this header with a call to the List Passes endpoint (/pass ). |
HTTP Response
All of the passes in a user's account are returned in the following JSON object.
Field | Type | Description |
---|---|---|
fare_options |
Array of FareOption objects |
Breakdown of fare options for grouping passes in user-displayable way. Only included if include_fare_options is true. |
passes |
Array of Pass objects |
All of the passes that belong to the logged-in user including any newly purchased passes. |
pass_books |
Array of PassBook objects |
All of the pass books that belong to the logged-in user including any newly purchased pass books. |
Response Headers
Name | Description |
---|---|
Token-Transit-Passes-State |
This header specifies the state of the passes in the account after the purchase. |
Purchasing and immediately activating a pass (User Authentication Required)
To purchase a pass and and activate a pass immediately , a POST
request supplying a valid fare_id
and purchase credentials should be sent to the pass purchase and activate endpoint.
HTTP Request
The following command assumes you have already sent a login request and saved cookies in
/tmp/tt_fake_api_cookies
curl -X POST \
-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 \
-d stripe_token=card_1234567890abcXYZ \
-d activate_on_purchase=true \
-d ticket_format=html_base64 \
"https://api.tokentransit.com/agency/bigbluebus/fare/regular_single_ride/purchase"
The above command returns JSON structured like this:
{
"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"
},
"display_html": "PGh0bWw+PGJvZHk+VG9rZW4gVHJhbnNpdCB0aWNrZXQ8L2JvZHk+PC9odG1sPg",
"end_timestamp": "2020-03-14T18:42:54.182663855-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_active",
"purchase_timestamp": "2020-03-14T16:42:54.182663855-07:00",
"start_timestamp": "2020-03-14T16:42:54.182663855-07:00",
"status": "active",
"ticket_expiration_timestamp": "2020-03-14T18:42:54.182663855-07:00"
}
The
start_timestamp
andend_timestamp
should be used to restrict the time in which a pass is allowed to be shown. Thedisplay_html
is what should be used to display the pass in the app for the user to board the bus (see "Displaying a pass"). Theuser_token
in the command may be pasted into jwt.io.
POST https://api.tokentransit.com/agency/{agency_id}/fare/{fare_id}/purchase
Path components
Path component | Description |
---|---|
agency_id |
Unique identifier for the agency. |
fare_id |
Unique identifier for the fare. |
Query Parameters
Parameter | Required/Default | Description |
---|---|---|
stripe_token |
Required | A Stripe token (begins with tok_ ) or source (may begin with card_ or acct_ ) corresponding to a user-supplied credit or debit card that Token Transit can use to charge a user for the purchase. |
activate_on_purchase |
true |
Boolean indicating whether the ticket should be activated on purchase or not. This must be set to true for this endpoint. If you wish to buy a pass and not activate it, use /purchase instead. |
ticket_format |
Required | html_base64 returns a ticket in base64-encoded HTML, html_raw returns a ticket with HTML simply with JSON string escaping, none omits the ticket_html field. |
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
A Pass
object will be returned representing the purchased pass.
Retrieving an existing pass (User Authentication Required)
Existing passes may be retrieved using the pass id for the specific pass. This endpoint can be called at any point to get fresh ticket HTML for a specific pass as long as the pass status is active
.
HTTP Request
The following command assumes you have already sent a login request and saved cookies in
/tmp/tt_fake_api_cookies
curl "https://api.tokentransit.com/pass/pass_unactivated" \
-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
The above command returns JSON structured like this
{
"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"
},
"end_timestamp": "2020-03-14T18:44:37.240024959-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_unactivated",
"purchase_timestamp": "2020-03-13T16:44:37.240024959-07:00",
"start_timestamp": "2020-03-14T16:44:37.240024959-07:00",
"status": "unactivated"
}
If the pass status is
active
,stale_ticket
, oractive_on_another_device
, thenstart_timestamp
andend_timestamp
should be used to restrict the time in which a pass should be shown as active to the user. If a pass isunactivated
, thenstart_timestamp
andend_timestamp
indicate when a pass would expire if the user were to activate it atstart_timestamp
. This endpoint can be used to fetch theend_timestamp
so it can be displayed to the user before they activate a pass. Thedisplay_html
is what should be used to display the pass in the app for the user to board the bus (see "Displaying a pass").
GET https://api.tokentransit.com/pass/{pass_id}
Path components
Path component | Description |
---|---|
pass_id |
Unique (base 64) identifier for pass returned after a successful purchase. |
Query Parameters
Parameter | Required/Default | Description |
---|---|---|
ticket_format |
html_base64 |
html_base64 returns a ticket in base64-encoded HTML, html_raw returns a ticket with HTML simply with JSON string escaping, none omits the ticket_html field. |
HTTP Response
A Pass
object will be returned representing the retrieved pass.
Retrieving an existing pass from a specific agency (User Authentication Required)
Existing passes may be retrieved using the pass id for the specific pass. This endpoint can be called at any point to get fresh ticket HTML for a specific pass as long as the pass status is active
.
HTTP Request
The following command assumes you have already sent a login request and saved cookies in
/tmp/tt_fake_api_cookies
curl "https://api.tokentransit.com/agency/bigbluebus/pass/pass_unactivated" \
-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
The above command returns JSON structured like this
{
"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"
},
"end_timestamp": "2020-03-14T18:47:09.639861731-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_unactivated",
"purchase_timestamp": "2020-03-13T16:47:09.639861731-07:00",
"start_timestamp": "2020-03-14T16:47:09.639861731-07:00",
"status": "unactivated"
}
If the pass status is
active
,stale_ticket
, oractive_on_another_device
, thenstart_timestamp
andend_timestamp
should be used to restrict the time in which a pass should be shown as active to the user. If a pass isunactivated
, thenstart_timestamp
andend_timestamp
indicate when a pass would expire if the user were to activate it atstart_timestamp
. This endpoint can be used to fetch theend_timestamp
so it can be displayed to the user before they activate a pass. Thedisplay_html
is what should be used to display the pass in the app for the user to board the bus (see "Displaying a pass").
GET https://api.tokentransit.com/agency/{agency_id}/pass/{pass_id}
Path components
Path component | Description |
---|---|
agency_id |
Unique identifier for the agency. |
pass_id |
Unique (base 64) identifier for pass returned after a successful purchase. |
Query Parameters
Parameter | Required/Default | Description |
---|---|---|
ticket_format |
html_base64 |
html_base64 returns a ticket in base64-encoded HTML, html_raw returns a ticket with HTML simply with JSON string escaping, none omits the ticket_html field. |
HTTP Response
A Pass
object will be returned representing the retrieved pass.
Retrieving all passes for a user (User Authentication Required)
Existing passes may be retrieved for a user. All passes will be shown even if the passes are not allowed to be displayed on your platform.
HTTP Request
The following command assumes you have already sent a login request and saved cookies in
/tmp/tt_fake_api_cookies
curl "https://api.tokentransit.com/pass?ticket_format=none&omit_unusabled_passes=false&include_fare_price=false" \
-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
The above command returns JSON structured like this
{
"pass_books": [
{
"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_3_ride",
"fare_name": "Regular 3 Ride",
"product_type": "single_pass"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_book_id": "book_regular_3_ride",
"purchase_timestamp": "2020-03-14T16:57:25.831550643-07:00",
"unactivated_remaining_count": 1
}
],
"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"
},
"end_timestamp": "2020-03-14T18:57:25.830610242-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_active",
"purchase_timestamp": "2020-03-14T16:57:25.830610242-07:00",
"start_timestamp": "2020-03-14T16:57:25.830610242-07:00",
"status": "active",
"ticket_expiration_timestamp": "2020-03-14T18:57:25.830610242-07:00"
},
{
"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"
},
"end_timestamp": "2020-03-14T18:57:25.831137186-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_unactivated",
"purchase_timestamp": "2020-03-13T16:57:25.831137186-07:00",
"start_timestamp": "2020-03-14T16:57:25.831137186-07:00",
"status": "unactivated"
},
{
"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"
},
"end_timestamp": "2020-03-14T18:57:25.831298674-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_active_on_another_device",
"purchase_timestamp": "2020-03-14T16:57:25.831298674-07:00",
"start_timestamp": "2020-03-14T16:57:25.831298674-07:00",
"status": "active_on_another_device",
"ticket_expiration_timestamp": "2020-03-14T18:57:25.831298674-07:00"
},
{
"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"
},
"end_timestamp": "2020-03-14T15:57:25.831343238-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_expired",
"purchase_timestamp": "2020-03-14T16:57:25.831343238-07:00",
"start_timestamp": "2020-03-14T13:57:25.831343238-07:00",
"status": "expired"
},
{
"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"
},
"end_timestamp": "2020-03-14T17:57:25.831379728-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_refunded",
"purchase_timestamp": "2020-03-14T16:57:25.831379728-07:00",
"start_timestamp": "2020-03-14T15:57:25.831379728-07:00",
"status": "refunded"
},
{
"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"
},
"end_timestamp": "2020-03-16T00:00:00-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_stale_ticket",
"purchase_timestamp": "2020-03-14T16:57:25.83141066-07:00",
"start_timestamp": "2020-03-13T16:57:25.83141066-07:00",
"status": "stale_ticket"
},
{
"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 3 Ride (1 Ride)"
},
"end_timestamp": "2020-03-14T15:57:25.831449513-07:00",
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_book_id": "book_regular_3_ride",
"pass_id": "pass_regular_3_ride.sub_pass_1",
"start_timestamp": "2020-03-14T13:57:25.831449513-07:00",
"status": "expired"
},
{
"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 3 Ride (1 Ride)"
},
"end_timestamp": "2020-03-14T18:57:25.831481892-07:00",
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_book_id": "book_regular_3_ride",
"pass_id": "pass_regular_3_ride.sub_pass_2",
"start_timestamp": "2020-03-14T16:57:25.831481892-07:00",
"status": "active",
"ticket_expiration_timestamp": "2020-03-14T18:57:25.831481892-07:00"
},
{
"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 3 Ride (1 Ride)"
},
"end_timestamp": "2020-03-14T18:57:25.83151315-07:00",
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_book_id": "book_regular_3_ride",
"pass_id": "pass_regular_3_ride.sub_pass_3",
"start_timestamp": "2020-03-14T16:57:25.83151315-07:00",
"status": "unactivated"
}
]
}
The
start_timestamp
andend_timestamp
should be used to restrict the time in which a pass is allowed to be used. You may cache thedisplay_html
untilticket_expiration_timestamp
, which indicates the last time the ticket may be shown to the user before requiring a refresh.
GET https://api.tokentransit.com/pass
Query Parameters
Parameter | Required/Default | Description |
---|---|---|
include_fare_options |
false |
If true, includes fare option info for each pass as well as a fare_options object. |
include_fare_price |
true |
If true, includes price of fare at the time of purchase. |
omit_unusable_passes |
true |
If true, only returns passes that might be usable by the user. |
ticket_format |
Required | html_base64 returns a ticket in base64-encoded HTML, html_raw returns a ticket with HTML simply with JSON string escaping, none omits the ticket_html field. |
HTTP Response
Field | Type | Description |
---|---|---|
fare_options |
Array of FareOption objects |
Breakdown of fare options for grouping passes in user-displayable way. Only included if include_fare_options is true. |
passes |
Array of Pass objects |
All of the passes that belong to the logged-in user. |
pass_books |
Array of PassBook objects |
All of the pass books that belong to the logged-in user. |
Activating an existing pass (User Authentication Required)
Existing passes may be activated using the following endpoint. Activating a pass will generate a ticket that can be shown by the user to the driver of a vehicle. The ticket will be contained in the display_html
part of the response. The field ticket_expiration_timestamp
indicates when this endpoint must be called again to retrieve a new ticket. However, this ticket may be cached until that point. The status stale_ticket
also indicates that a pass must be reactivated.
Activation will not always succeed. Consult the table in Pass Statuses to determine, which passes may be successfully activated. Of particular note is the pass_active_on_another_device
status. This status indicates that the pass has already been activated by this user on another device. For security reasons, a user's pass may only be active on one device at once.
HTTP Request
The following command assumes you have already sent a login request and saved cookies in
/tmp/tt_fake_api_cookies
curl -X POST \
-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 \
-d include_fare_price=false \
-d ticket_format=html_base64 \
-d omit_unusable_passes=false \
"https://api.tokentransit.com/pass/pass_unactivated/activate"
The above command returns JSON structured like this
{
"activated_pass_id": "pass_unactivated",
"pass_books": [
{
"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_3_ride",
"fare_name": "Regular 3 Ride",
"product_type": "single_pass"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_book_id": "book_regular_3_ride",
"purchase_timestamp": "2020-03-14T17:10:34.452193315-07:00",
"unactivated_remaining_count": 1
}
],
"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"
},
"display_html": "PGh0bWw+PGJvZHk+VG9rZW4gVHJhbnNpdCB0aWNrZXQ8L2JvZHk+PC9odG1sPg",
"end_timestamp": "2020-03-14T19:10:34.451370137-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_active",
"purchase_timestamp": "2020-03-14T17:10:34.451370137-07:00",
"start_timestamp": "2020-03-14T17:10:34.451370137-07:00",
"status": "active",
"ticket_expiration_timestamp": "2020-03-14T19:10:34.451370137-07:00"
},
{
"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"
},
"display_html": "PGh0bWw+PGJvZHk+VG9rZW4gVHJhbnNpdCB0aWNrZXQ8L2JvZHk+PC9odG1sPg",
"end_timestamp": "2020-03-14T19:10:34.451858149-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_unactivated",
"purchase_timestamp": "2020-03-13T17:10:34.451858149-07:00",
"start_timestamp": "2020-03-14T17:10:34.451858149-07:00",
"status": "active",
"ticket_expiration_timestamp": "2020-03-14T19:10:34.451858149-07:00"
},
{
"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"
},
"end_timestamp": "2020-03-14T19:10:34.451916788-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_active_on_another_device",
"purchase_timestamp": "2020-03-14T17:10:34.451916788-07:00",
"start_timestamp": "2020-03-14T17:10:34.451916788-07:00",
"status": "active_on_another_device",
"ticket_expiration_timestamp": "2020-03-14T19:10:34.451916788-07:00"
},
{
"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"
},
"end_timestamp": "2020-03-14T16:10:34.451954083-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_expired",
"purchase_timestamp": "2020-03-14T17:10:34.451954083-07:00",
"start_timestamp": "2020-03-14T14:10:34.451954083-07:00",
"status": "expired"
},
{
"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"
},
"end_timestamp": "2020-03-14T18:10:34.451998482-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_refunded",
"purchase_timestamp": "2020-03-14T17:10:34.451998482-07:00",
"start_timestamp": "2020-03-14T16:10:34.451998482-07:00",
"status": "refunded"
},
{
"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"
},
"end_timestamp": "2020-03-16T00:00:00-07:00",
"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"
},
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_id": "pass_stale_ticket",
"purchase_timestamp": "2020-03-14T17:10:34.452049739-07:00",
"start_timestamp": "2020-03-13T17:10:34.452049739-07:00",
"status": "stale_ticket"
},
{
"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 3 Ride (1 Ride)"
},
"end_timestamp": "2020-03-14T16:10:34.452083442-07:00",
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_book_id": "book_regular_3_ride",
"pass_id": "pass_regular_3_ride.sub_pass_1",
"start_timestamp": "2020-03-14T14:10:34.452083442-07:00",
"status": "expired"
},
{
"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 3 Ride (1 Ride)"
},
"display_html": "PGh0bWw+PGJvZHk+VG9rZW4gVHJhbnNpdCB0aWNrZXQ8L2JvZHk+PC9odG1sPg",
"end_timestamp": "2020-03-14T19:10:34.452124076-07:00",
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_book_id": "book_regular_3_ride",
"pass_id": "pass_regular_3_ride.sub_pass_2",
"start_timestamp": "2020-03-14T17:10:34.452124076-07:00",
"status": "active",
"ticket_expiration_timestamp": "2020-03-14T19:10:34.452124076-07:00"
},
{
"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 3 Ride (1 Ride)"
},
"end_timestamp": "2020-03-14T19:10:34.452163203-07:00",
"logo_url": "https://storage.googleapis.com/token-transit.appspot.com/myzToIABwReXJuY3z6e4KEGPXx1vOEAP3ZbYD9isQlE-logo.png",
"pass_book_id": "book_regular_3_ride",
"pass_id": "pass_regular_3_ride.sub_pass_3",
"start_timestamp": "2020-03-14T17:10:34.452163203-07:00",
"status": "unactivated"
}
]
}
All passes are returned in this request (if successful). As in other calls, the
start_timestamp
andend_timestamp
should be used to restrict the time in which a pass is allowed to be used. You may cache thedisplay_html
untilticket_expiration_timestamp
, which indicates the last time the ticket may be shown to the user before requiring a refresh.
POST https://api.tokentransit.com/pass/{pass_id}/activate
Path components
Path component | Description |
---|---|
pass_id |
Unique identifier for the pass. |
Query parameters
Parameter | Required/Default | Description |
---|---|---|
include_fare_options |
false |
If true, includes fare option info for each pass as well as a fare_options object. |
include_fare_price |
true |
If true, includes price of fare at the time of purchase. |
ticket_format |
Required | html_base64 returns a ticket in base64-encoded HTML, html_raw returns a ticket with HTML simply with JSON string escaping, none omits the ticket_html field. |
omit_unusable_passes |
true |
If true, only returns passes that might be usable by the user. |
HTTP Response
All of the passes in a user's account are returned in the following JSON object.
Field | Type | Description |
---|---|---|
activated_pass_id |
string |
The ID of the pass that was activated. In certain cases, this may be different from the one requested for activation but will always be one of the passes included in the result. |
fare_options |
Array of FareOption objects |
Breakdown of fare options for grouping passes in user-displayable way. Only included if include_fare_options is true. |
passes |
Array of Pass objects |
All of the passes that belong to the logged-in user including the newly activated pass. |
pass_books |
Array of PassBook objects |
All of the pass books that belong to the logged-in user. |
Response Headers
Name | Description |
---|---|
Token-Transit-Passes-State |
This header specifies the state of the passes in the account after the activation. |
Redemptions
A redemption is an action where the user is able to change the state of their account (e.g. add passes or unlock restricted passes) by redeeming a link.
Redemption is performed by the user by following a deeplink to your app. After following the deeplink, information about the redemption can be retrieved by the redeeming app as well letting the user redeem the contents.
Setting up a redemption link schema
In order to use redemption, you will have to register a redemption link deeplink format with us and respond to these deeplinks in your app. The deeplink must have the following format:
https://{domain}/{prefix}/redeem
The prefix
part of the URL path can be any path that you wish to use including the root path. However, the full path must end in /redeem
.
Please notify us of the schema you decide to use once you choose one.
Testing redemption links
The following are valid redemption links in test. You can just send them in the link
parameter in the following calls:
Link | ErrorCode | Behavior |
---|---|---|
test_redemption_already_used |
redemption_already_used |
Fails with error code redemption_already_used if logged in or error code redemption_used_by_another_account if not logged in. |
test_redemption_ineligible |
redemption_ineligible |
Fails with error code redemption_ineligible if logged in. There is no error if not logged in. |
test_redemption_invalid |
redemption_invalid |
Fails with error code redemption_invalid |
test_redemption_limits_exceeded |
redemption_limits_exceeded |
Fails with error code redemption_limits_exceeded if logged in. There is no error if not logged in. |
test_redemption_into_source_account |
pass_transfer_into_source_account |
Fails with error code pass_transfer_into_source_account if logged in. There is no error if not logged in. |
test_redemption_success |
None | Redemption will succeed |
test_redemption_used_by_another_account |
redemption_used_by_another_account |
Fails with error code redemption_used_by_another_account . |
Redemption UX
Upon deeplink into your app, we recommend that you show a user a dialog or screen with a header, a body and two options.
The header should come from the title
field of the GET /redeem
response. The body should come from message message
field of the GET /redeem
response.
If the user is logged in, then there should ideally be two buttons:
- Redeem - A
POST /redeem
call should be made, and the user's wallet should be refreshed viaGET /pass
- Cancel - The
universal_url
link should be opened up in the user's browser.
If the user is not logged in, then there should ideally be two buttons:
- Login to Redeem - User would be taken to a login page. Once they are logged in, they should be shown the redemption page again
- Cancel - The
universal_url
link should be opened up in the user's browser.
Retrieving redemption information
Information about the redemption can be retrieved beform the redemption is performed. This is structed in the format of a title and message in the user's language. A user does not have to be logged in.
HTTP Request
curl "https://api.tokentransit.com/redeem?link=redemption.link" \
-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
The above command returns JSON structured like this
{
"title": "Redeem Fares",
"message": "The following fares will be made available in your account:\n - Adult Single Ride, Quantity: 1"
}
GET https://api.tokentransit.com/redeem
Query Parameters
Parameter | Required/Default | Description |
---|---|---|
link |
Required | The exact link including query parameters that the user followed to deeplink into your app. |
text_mime_type |
text/plain |
The desired mime type of the message field in the response. Supported options are text/plain and text/html . |
HTTP Response
A description of what is contained in the redemption.
Field | Type | Description |
---|---|---|
title |
string |
A title to display to the user in a modal. |
message |
string |
The body of the message to display to the user in a modal. |
code |
string |
The code from the link. |
universal_url |
string |
A URL that can be opened in a browser to show the user all of the possible apps that can be used to redeem. |
agency |
Agency object |
An agency object may be returned if the redemption is associated with a specific agency. May be omitted if the redemption is not associated with an agency. |
Redeeming a link (User Authentication Required)
Redeeming a link will execute logic that will affect the user's account state. This may include allowing access to restricted passes or adding passes to a user's account.
HTTP Request
curl -X POST \
-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 \
-d link=redemption.link \
"https://api.tokentransit.com/redeem"
The above command returns JSON structured like this
{}
POST https://api.tokentransit.com/redeem
Query Parameters
Parameter | Required/Default | Description |
---|---|---|
link |
Required | The exact link including query parameters that the user followed to deeplink into your app. |
HTTP Response
The response will always be an empty JSON object upon success.
Validations
Validations refer to the process where the user proves that they have the pass required to ride a particular vehicle.
Visual Validation
Visual validation is validation performed by the rider showing the vehicle operator a valid ticket from the display_html
field in the Pass
object. Information about these validations can be reported to Token Transit.
Logging a visual validation (User Authentication Required)
Logs a visual validation to the server including the pass validated, user's location, and current time. This should be sent every time the user taps to show the ticket html even if this happens in short succession.
HTTP Request
curl -X POST \
-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 \
-d pass_id=pass_active \
--data-urlencode timestamp="2020-03-14T17:00:01-07:00" \
-d latitude=37.773972 \
-d longitude=-122.431297 \
"https://api.tokentransit.com/validation/visual"
The above command returns JSON structured like this
{}
POST https://api.tokentransit.com/validation/visual
Query Parameters
Parameter | Required/Default | Description |
---|---|---|
pass_id |
Required | The id of the pass that the user tapped for validation. |
latitude |
0.0 | Decimal number indicating the latitude that user validated the pass. If the latitude could not be acquired, the validation should still be logged but this parameter may be omitted. |
longitude |
0.0 | Decimal number incating the longitude that the suer validated the pass. If the latitude could not be acquired, the validation should still be logged but this parameter may be omitted. |
timestamp |
Required | Time of validation (in RFC 3339). Time may include milliseconds microseconds, or nanoseconds. |
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 validation report. Specifying an idempotency key will help us ensure that the validation is only counted once. |
HTTP Response
The response will always be an empty JSON response upon success.
Misc
Displaying Content
Displaying a pass purchase screen
It is recommended that you show the user all of the fares using selectors for different FareOption
s. These should be shown in the order that is returned in the fare_options
field from a called to the List Fares endpoint. Remember that not all combinations of options will yield a valid fare. Care should be taken to make sure that the each selector is only populated with options that when combined with the previous option still yield available fares.
Displaying the user's passes
Many of the API calls return a user's passes. It is recommended that you show all of the user's passes in a single (scrollable) screen that represents the user's pass wallet. It is recommended that you show active passes at the top and unactivated passes below. Passes that are expired or refunded should not be shown here but instead in a separate screen in the app.
Displaying a pass for boarding
Part of the return value of a pass is the display_html
field in the JSON that contains the HTML to display to the user. This can be requested in either raw HTML or base64-encoded HTML. The HTML returned from this should be shown to the user in an web view.
Integrating with Stripe
All our our payments are processed through Stripe. The purchase endpoint accepts a number of different types of Stripe payment credentials via the stripe_token
parameter including payment methods, sources, and tokens.
The difference between a Stripe token, a Stripe source, and a Stripe payment method is that the source and payment method are reusable while the token is not. A Stripe source or payment method will always be returned upon purchase.
Stripe SDK/Web API Integration
The easiest way to integrate with Stripe is to follow the Stripe guide. However, once you get to step 3, you will want to just send the payment method via the /purchase
endpoint via the stripe_token
param. Do not follow the remaining steps for now.
Spreedly / Other Vault Integration
This integration assumes you are using a credit card vault (such as spreedly). In this integration we will give you a special Stripe key that must only be used by the server. This key should let you make the required stripe calls. Here are the docs for the vaults that we know about.
- Spreedly
store
- You will send over acustomer_id
via Spreedly Stripe integration and receive back a stripesource
that can be passed in thestripe_token
parameter to our purchase API. The Stripe customer id may be retrieved from thePOST /user/login
endpoint.