Skip to content

Instantly share code, notes, and snippets.

@charleyhine
Last active December 21, 2022 08:55
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save charleyhine/6e965337e52398d53be5 to your computer and use it in GitHub Desktop.
Save charleyhine/6e965337e52398d53be5 to your computer and use it in GitHub Desktop.
Shift API

Shift API

Custodians (companies and developers) integrate with the Shift API to create and manage branded debit cards and cardholder data. We've tried to make this documentation user-friendly and example-filled, but please drop us a line with any questions. If you're planning to use our API in production, you should take a look at Metropolitan Commercial Bank's privacy policy.

Guide

Integration Options

When a cardholder uses his or her Shift Card to purchase goods or services, Shift's software must quickly confirm the cardholder has sufficient funds prior to authorizing the transaction. A cardholder's spendable balance can be exposed from a custodian's API -or- mainly reside within Shift.

Custodian API provides spendable balance acting as the infallible balance authority. In this case, Shift will request the user's current spendable balance from the custodian's API (your software). Shift will perform basic performance testing of your API prior to launch. Please reach out to Shift Support to discuss integration specifics.

-OR-

Shift stores a spendable balance for each cardholder. Your service simply updates each cardholder spendable balance as it changes within your business logic by consuming Shift's Cardholder Balances.

Lay of the land

The Shift API is architected around REST, using standard HTTP verbs to communicate and HTTP response codes to indicate status and errors. All responses come in standard JSON. The Shift API is served over HTTPS to ensure data privacy; HTTP is not supported. Every request must include your secret API key. Request data must be included in the body.

API Endpoint

https://api.shiftpayments.com

Authentication

Authentication to the API occurs via HTTP Basic Auth. Provide your API publishable key as the basic auth username and the your API secret key as the password.

Live mode and testing

Every account is divided into two universes: one for testing, and one for running on your live website. All API requests exist in one of those two universes, and objects in one universe cannot be manipulated by objects in the other.

Errors

status code 401

{
  "error": {
    "type": "invalid_request_error",
    "message": "Authentication to the API occurs via HTTP Basic Auth"
  }
}
status code 400

{
  "error": {
    "type": "invalid_request_error",
    "message": "Invalid region provided (must be US two letter state)"
  }
}

Cardholders

Use the /cardholders endpoint to create and manage Shift cardholders. Cardholder objects allow you to track application status and confirm basic customer info. You can retrieve individual cardholders as well as a list of all your cardholders.

Know Your Customer

Each cardholder object inlcudes a kyc_status. This represents the current state of a user's 'Know Your Customer' identity verification process. More context around a cardholder's kyc_status is provided with specific (and separate) reason groups.

KYC key Potential Values
kyc_status RESUBMIT_DETAILS, UPLOAD_FILE, UNDER_REVIEW, PASSED, REJECTED, TEMPORARY_ERROR
kyc_identity_reason null, WATCHLIST_MATCH, SSN_MISMATCH, SSN_INVALID
kyc_address_reason null, ADDRESS_COMMERCIAL, ADDRESS_PO_BOX, ADDRESS_RISKY
kyc_file_reason null, UNRELATED_FILE, WRONG_FILE, BLURRY

KYC reasons will all have a null value when kyc_status is PASSED

Create a cardholder

POST /cardholders

In test mode:

  • New users and cards are created but cards are not physically shipped and will not work over the Visa network.
  • kyc_status is returned as PASSED when the last 4 digits of the provided SSN are '0000'.

Arguments

Parameter Type Details
first_name required
last_name required
email required
phone_number required E.164 number formatting
address required International address object
date_of_birth required ISO8601 Date format
document required Identity document object
custodian_uid optional Unique identifier of custodian's user
design_key optional Shift card design key string

Example Request Body

{
	"first_name": "Josh",
	"last_name": "Wilson",
	"custodian_uid": "your-external-user-id",
	"email": "pat@wilson.com",
	"phone_number": "6157915911",
	"date_of_birth": "1982-06-20",
	"design_key": "blue",
	"address": {
		"street_one": "1800 Gates Ave",
		"street_two": "2L",
		"locality": "Ridgewood",
		"region": "NY",
		"postal_code": "11385",
		"country": "USA"
	},
	"document": {
		"type": "SSN",
		"value": "490940000"
	}
}

Example Response:

status code 200

{
	"cardholder": {
		"livemode": false,
		"id": "crdhldr_1cd68f70917cb5ed",
		"email": "pat@wilson.com",
		"kyc_passed_at": "2016-10-19T23:20:21.034+00:00",
		"kyc_status": "PASSED",
		"kyc_identity_reason": null,
		"kyc_address_reason": null,
		"kyc_file_reason": null,
		"first_name": "Josh",
		"last_name": "Wilson",
		"phone": 6157915911,
		"custodian_uid": "your-external-user-id",
		"cards": [{
			"card": {
				"id": "crd_c7015aecb8a05618",
				"design_key": "blue",
				"livemode": false,
				"wallets": [],
				"last_four": "5542",
				"status": "CREATED",
				"activated_at": null,
				"created_at": "2016-10-19T23:20:19+00:00",
				"cardholder_id": "crdhldr_1cd68f70917cb5ed"
			}
		}],
		"created_at": "2016-10-19T23:20:17+00:00"
	}
}

Retrieve a cardholder

GET /cardholders/[cardholder_id]

Arguments

Parameter Type Details
cardholder required The identifier of the customer to be retrieved.

List all cardholders

GET /cardholders

Arguments

Parameter Type Details
limit optional A limit on the number of objects to be returned. Limit can range between 1 and 100 items.
ending_before optional A cursor for use in pagination. An object ID that defines your place in the list.
starting_after optional A cursor for use in pagination. An object ID that defines your place in the list.

Example Response:

status code 200

{
	"cardholders": [
		{"cardholder": ... }, 
		{"cardholder": ... }
	}],
	"has_more": true
}

Create a cardholder transaction (testmode only)

POST /cardholders/[cardholder_id]/transactions

Arguments

Parameter Type Details
cardholder required The identifier of the cardholder.
usd_amount required USD decimal representing transaction amount.

Example Request Body:

{
  "usd_amount": 200.00
}

Example Response:

status code 200

{
	"transaction": {
		"livemode": false,
		"id": "txn_12aa2c96a548d7d2",
		"authorizations": [],
		"adjustments": [],
		"cardholder_id": "crdhldr_1cd68f70917cb5ed",
		"created_at": "2016-10-19T23:25:17+00:00",
		"cardholder_email": "pat@wilson.com",
		"cardholder_first_name": "Josh",
		"cardholder_last_name": "Wilson",
		"card_id": "crd_c7015aecb8a05618",
		"description": "",
		"merchant_name": null,
		"merchant_locality": null,
		"merchant_region": null,
		"merchant_country": null,
		"mcc": "7299",
		"mcc_name": "Undefined",
		"merchant_id": null,
		"state": "pending",
		"context": "PIN purchase (VISA, Signature)",
		"local_amount": 200.0,
		"local_currency": null,
		"usd_amount": 200.0,
		"cashback_amount": null
	}
}

List all cardholder transactions

GET /cardholders/[cardholder_id]/transactions

Arguments

Parameter Type Details
cardholder required The identifier of the customer to be retrieved.
limit optional A limit on the number of objects to be returned. Limit can range between 1 and 100 items.
ending_before optional A cursor for use in pagination. An object ID that defines your place in the list.
starting_after optional A cursor for use in pagination. An object ID that defines your place in the list.

Example Response:

status code 200

{
	"transactions": [
		{"transaction": ... }, 
		{"transaction": ... }
	}],
	"has_more": true
}

Balances

The ability to manage multiple spendable balances (buckets) and deposits for each cardholder.

Retrieve a cardholder balances

GET /cardholders/[cardholder_id]/balances

Arguments

Parameter Type Details
cardholder required The identifier of the customer to be retrieved.

Example Response:

status code 200

{
	"balances": [{
		"balance": {
			"key": "default",
			"cardholder_id": "crdhldr_7hw62d8",
			"livemode": true,
			"usd_balance": 100.00,
			"usd_spendable": 25.0,
			"usd_held": 75.00
		}
	}]
}

Update a cardholder's spendable balance

Ability for a custodian to set the absolute spendable dollar amount for a cardholder.

PUT /cardholders/[cardholder_id]/balances

Arguments

Parameter Type Details
cardholder required The identifier of the customer to be retrieved.
usd_amount required USD amount the cardholder shall be able to spend.
balance_key optional Specific balance identifier or bucket string.

Example Request Body

{
  "usd_amount": 300.00,
}

Example Response:

status code 200

{
	"balance": {
		"key": "default",
		"cardholder_id": "crdhldr_7hw62d8",
		"livemode": true,
		"usd_balance": 375.00,
		"usd_spendable": 300.0,
		"usd_held": 75.00
	}
}

Create a cardholder balance deposit

POST /cardholders/[cardholder_id]/balances/deposits

Arguments

Parameter Type Details
cardholder required The identifier of the customer to be retrieved.
usd_amount required USD amount the cardholder shall be able to spend.
balance_key optional Specific balance identifier or bucket string.

Example Request Body

{
  "usd_amount": 50.00,
}

Example Response:

status code 200

{
	"balance": {
		"key": "default",
		"cardholder_id": "crdhldr_7hw62d8",
		"livemode": true,
		"usd_balance": 425.00,
		"usd_spendable": 350.0,
		"usd_held": 75.00
	}
}

Cards

Use the /cards endpoint to retrieve and adjust Shift cardholder cards.

status for a given card object can be one of four states: CREATED, ACTIVATED, DEACTIVATED, or CLOSED

Retrieve a card

GET /cards/[card_id]

Arguments

Parameter Type Details
card required The identifier of the cardholder's card.

Example Response:

status code 200

{
	"card": {
		"id": "crd_fde2d61d233455b9",
		"design_key": "blue",
		"livemode": true,
		"wallets": [{
			"wallet": {
				"name": "Wilson*s iPhone",
				"type": "iPhone",
				"status": "ACTIVE"
			}
		}],
		"last_four": "9497",
		"status": "ACTIVATED",
		"activated_at": "2016-09-27T01:46:32+00:00",
		"created_at": "2016-09-27T00:54:09+00:00",
		"cardholder_id": "crdhldr_2d0a6443e5da6ba7"
	}
}

Wallet lifecycle

Status Description
INACTIVE Provisioned with wallet provider, but not yet active
ACTIVE Active wallet / card instance
SUSPENDED Temporarily unusable
DELETED Permanently unusable

Change card PIN

PUT /cards/[card_id]

Arguments

Parameter Type Details
card required The identifier of the cardholder's card.
new_pin required 4-digit card pin.

Change card status

PUT /cards/[card_id]/[action]

Arguments

Parameter Type Details
card required The identifier of the cardholder's card.
action required One of the following strings: "ACTIVATE", "DEACTIVATE", "OPEN" or "CLOSE".

Example Response:

status code 200

{
	"card": {
		"id": "crd_fde2d61d233455b9",
		"design_key": "blue",
		"livemode": true,
		"wallets": [{
			"wallet": {
				"name": "Wilson*s iPhone",
				"type": "iPhone",
				"status": "ACTIVE"
			}
		}],
		"last_four": "9497",
		"status": "DEACTIVATED",
		"activated_at": "2016-09-27T01:46:32+00:00",
		"created_at": "2016-09-27T00:54:09+00:00",
		"cardholder_id": "crdhldr_2d0a6443e5da6ba7"
	}
}

Transactions

Use the /transactions endpoint to retrieve Shift cardholder currency movement records.

Each transaction object inlcudes state represetning the current state of a transaction's lifecycle. state can be one of three values: pending, complete or declined.

Retrieve a transaction

GET /transactions/[transaction_id]

Arguments

Parameter Type Details
transaction required The identifier of the transaction to be retrieved.

Example Response:

status code 200

{
	"transaction": {
		"livemode": true,
		"id": "txn_5450e1c020e5533f",
		"authorizations": [{
			"authorization": {
				"id": "auth_92b91bf7d31bf97b",
				"authorized": true
			}
		}],
		"adjustments": [{
			"adjustment": {
				"id": "adj_c96794956acc0b80",
				"created_at": "2016-10-19T16:54:55+00:00",
				"usd_amount": 1.26
			}
		}],
		"cardholder_id": "crdhldr_21044d185f9edb68",
		"created_at": "2016-10-19T16:54:49+00:00",
		"cardholder_email": "mac@macdemarco.com",
		"cardholder_first_name": "Mac",
		"cardholder_last_name": "Demarco",
		"card_id": "crd_a38d4d15e8978373",
		"description": "STARBUCKS STORE 05757 SAN FRANCISCOCAUSA",
		"merchant_name": "STARBUCKS STORE 05757",
		"merchant_locality": "SAN FRANCISCO",
		"merchant_region": "CA",
		"merchant_country": "USA",
		"mcc": "5814",
		"mcc_name": "Fast Food Restaurants",
		"state": "pending",
		"context": "Uncategorized (VISA, Signature)",
		"local_amount": 1.95,
		"local_currency": "USD",
		"usd_amount": 1.95,
		"cashback_amount": 0.0,
		"card_present": false,
		"ecommerce": false,
		"international": false,
		"emv": false,
		"network": "VISA",
		"dispute_at": null,
		"dispute_won_at": null,
		"dispute_lost_at": null
	}
}

List all transactions

GET /transactions

Arguments

Parameter Type Details
limit optional A limit on the number of objects to be returned. Limit can range between 1 and 100 items.
ending_before optional A cursor for use in pagination. An object ID that defines your place in the list.
starting_after optional A cursor for use in pagination. An object ID that defines your place in the list.

Example Response:

status code 200

{
  "transactions": [
    {...}, 
    {...}
  ],
  "has_more": false
}

Authorizations

Example Request:

{
	"authorization": {
		"id": "auth_98ufn66",
		"transaction_id": "txn_e17b188582494880",
		"cardholder_id": "crdhldr_87fndgs5",
		"card_id": "crd_iuhsf7fh",
		"description": "ESSEN NEW YORK NYUSA",
		"merchant_name": "ESSEN",
		"merchant_locality": "NEW YORK",
		"merchant_region": "NY",
		"merchant_country": "USA",
		"mcc": "5812",
		"mcc_name": "Eating Places, Restaurants",
		"state": "pending",
		"local_amount": 8.79,
		"local_currency": "USD",
		"usd_amount": 8.79,
		"cardholder_usd_balance": nil,
		"authorized": nil
	}
}

Example Response:

{
	"authorization": {
		"id": "auth_98ufn66",
		"transaction_id": "txn_e17b188582494880",
		"cardholder_id": "crdhldr_87fndgs5",
		"card_id": "crd_iuhsf7fh",
		"description": "ESSEN NEW YORK NYUSA",
		"merchant_name": "ESSEN",
		"merchant_locality": "NEW YORK",
		"merchant_region": "NY",
		"merchant_country": "USA",
		"mcc": "5812",
		"mcc_name": "Eating Places, Restaurants",
		"state": "pending",
		"local_amount": 8.79,
		"local_currency": "USD",
		"usd_amount": 8.79,
		"cardholder_usd_balance": 7004.24,
		"authorized": true
	}
}

Settlements

Use the /settlements endpoint to retrieve daily settlement details.

Retrieve last settlement

GET /settlements

Example Response:

status code 200

{
	"settlement": {
		"livemode": true,
		"id": "stlmnt_5hfi35",
		"date": "2016-05-24T16:36:24+00:00",
		"total_balance_due": 56943.05,
		"period_balance_due": 6281.39,
		"csv_url": "https://example.shiftpayments.com/settlements/stlmnt_5hfi35"
	}
}

Settlement CSV

The daily settlement CSV lists every financial or reversal card network message from the previous day (PST). Note that two rows can have the same transaction_id (e.g. capture message and reversal message).

Column Description
transaction_id Shift transaction identifier
cardholder_id Shift cardholder identifier
transaction_state Current state of the Shift transaction
usd_amount Current settled amount in USD
visa_interchange Gross Visa interchange amount

Webhooks

The Shift API can push real-time data directly to your application server. Use webhooks to be notified about events that happen with your account and cardholders including transaction authorization, transaction updates and settlement information.

Creating a webhoook endpoint on your server is no different from creating any page on your website. With PHP, you might create a new .php file on your server; with a framework like Sinatra, you would add a new route with the desired URL.

To acknowledge receipt of a webhook, your endpoint should return a 2xx HTTP status code. Any other information returned in the request headers or request body is ignored. All response codes outside this range, including 3xx codes, will indicate to Shift that you did not receive the webhook.

If a webhook is not successfully received for any reason, Shift will continue trying to send the webhook once an hour for up to 2 days. For any webhook that failed initially, upon retry each hour, the latest state for the Shift object will be sent.

KYC Status Updates

status code 200

{
	"cardholder": {
		"livemode": false,
		"id": "crdhldr_1cd68f70917cb5ed",
		"email": "pat@wilson.com",
		"event": "kyc_status_update",
		"kyc_passed_at": "2016-10-19T23:20:21.034+00:00",
		"kyc_status": "PASSED",
		"kyc_identity_reason": null,
		"kyc_address_reason": null,
		"kyc_file_reason": null,
		"first_name": "Josh",
		"last_name": "Wilson",
		"phone": 6157915911,
		"custodian_uid": "your-external-user-id",
		"cards": [{
			"card": {
				"id": "crd_c7015aecb8a05618",
				"design_key": "blue",
				"livemode": false,
				"wallets": [],
				"last_four": "5542",
				"status": "CREATED",
				"activated_at": null,
				"created_at": "2016-10-19T23:20:19+00:00",
				"cardholder_id": "crdhldr_1cd68f70917cb5ed"
			}
		}],
		"created_at": "2016-10-19T23:20:17+00:00"
	}
}

Card Updates

{
	"card": {
		"id": "crd_fde2d61d233455b9",
		"design_key": "blue",
		"livemode": true,
		"event": "pin_update",
		"wallets": [{
			"wallet": {
				"name": "Wilson*s iPhone",
				"type": "iPhone",
				"status": "ACTIVE"
			}
		}],
		"last_four": "9497",
		"status": "ACTIVATED",
		"activated_at": "2016-09-27T01:46:32+00:00",
		"created_at": "2016-09-27T00:54:09+00:00",
		"cardholder_id": "crdhldr_2d0a6443e5da6ba7"
	}
}

Daily Settlement

{
	"settlement": {
		"livemode": true,
		"id": "stlmnt_5hfi35",
		"date": "2016-05-24T16:36:24+00:00",
		"total_balance_due": 56943.05,
		"period_balance_due": 6281.39,
		"csv_url": "https://example.shiftpayments.com/settlements/stlmnt_5hfi35"
	}
}

Transaction Updates

{
	"transaction": {
		"livemode": true,
		"id": "txn_5450e1c020e5533f",
		"authorizations": [{
			"authorization": {
				"id": "auth_92b91bf7d31bf97b",
				"authorized": true
			}
		}],
		"adjustments": [{
			"adjustment": {
				"id": "adj_c96794956acc0b80",
				"created_at": "2016-10-19T16:54:55+00:00",
				"usd_amount": 1.26
			}
		}],
		"cardholder_id": "crdhldr_21044d185f9edb68",
		"created_at": "2016-10-19T16:54:49+00:00",
		"cardholder_email": "mac@macdemarco.com",
		"cardholder_first_name": "Mac",
		"cardholder_last_name": "Demarco",
		"card_id": "crd_a38d4d15e8978373",
		"description": "STARBUCKS STORE 05757 SAN FRANCISCOCAUSA",
		"merchant_name": "STARBUCKS STORE 05757",
		"merchant_locality": "SAN FRANCISCO",
		"merchant_region": "CA",
		"merchant_country": "USA",
		"mcc": "5814",
		"mcc_name": "Fast Food Restaurants",
		"state": "pending",
		"context": "Uncategorized (VISA, Signature)",
		"local_amount": 1.95,
		"local_currency": "USD",
		"usd_amount": 1.95,
		"cashback_amount": 0.0,
		"card_present": false,
		"ecommerce": false,
		"international": false,
		"emv": false,
		"network": "VISA",
		"dispute_at": null,
		"dispute_won_at": null,
		"dispute_lost_at": null
	}
}
@lixulplick
Copy link

lixulplick commented Jul 22, 2016

Love it.

@christoph3
Copy link

I love it too and trying to figure it all out. Any suggestions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment