Skip to content

Instantly share code, notes, and snippets.

@fnky
Last active October 10, 2024 11:40
Show Gist options
  • Save fnky/76f533366f75cf75802c8052b577e2a5 to your computer and use it in GitHub Desktop.
Save fnky/76f533366f75cf75802c8052b577e2a5 to your computer and use it in GitHub Desktop.
Stripe keys and IDs
Prefix Description Notes
ac_ Platform Client ID Identifier for an auth code/client id.
acct_ Account ID Identifier for an Account object.
aliacc_ Alipay Account ID Identifier for an Alipay account.
ba_ Bank Account ID Identifier for a Bank Account object.
btok_ Bank Token ID Identifier for a Bank Token object.
card_ Card ID Identifier for a Card object.
cbtxn_ Customer Balance Transaction ID Identifier for a Customer Balance Transaction object.
ch_ Charge ID Identifier for a Charge object.
cn_ Credit Note ID Identifier for a Credit Note object.
cs_live_ Live Checkout Session ID Identifier for a checkout Session object in live mode.
cs_test_ Test Checkout Session ID Identifier for a checkout Session object in test mode.
cus_ Customer ID Identifier for a Customer object.
dp_ Dispute ID Identifier for a Dispute object.
evt_ Event ID Identifier for an Event object.
fee_ Application Fee ID Identifier for an Application Fee object.
file_ File ID Identifier for a File object.
fr_ Application Fee Refund ID Identifier for an Application Fee Refund object.
iauth_ Issuing Authorization ID Identifier for an Issuing Authorization object.
ic_ Issuing Card ID Identifier for an Issuing Card object.
ich_ Issuing Card Holder ID Identifier for an Issuing Card Holder object.
idp_ Issuing Dispute ID Identifier for an Issuing Dispute object.
ii_ Invoice Item ID Identifier for an Invoice Item object.
il_ Invoice Line Item ID Identifier for a Invoice Line Item object.
in_ Invoice ID Identifier for an Invoice object.
ipi_ Issuing Transaction ID Identifier for an Issuing Transaction object.
link_ File Link ID Identifier for a File Link object.
or_ Order ID Identifier for an Order object.
orret_ Order Return ID Identifier for an Order Return object.
person_ Person ID Identifier for a Person object.
pi_ Payment Intent ID Identifier for a Payment Intent object.
pk_live_ Live public key Public key in a live environment.
pk_test_ Test public key Public key in a test environment.
pm_ Payment Method ID Identifier for a Payment Method object.
po_ Payout ID Identifier for a Payout object.
price_ Price ID Identifier for a Price object.
prod_ Product ID Identifier for a Product object.
prv_ Review ID Identifier for a Review object.
pst_live_ Live Connection token Connection token in a live environment.
pst_test_ Test Connection token Connection token in a test environment.
py_ Payment ID Identifier for a Payment object.
pyr_ Payment Refund ID Identifier for a psuedo Refund object of a payment.
qt_ Quote ID Identifier for a Quote object.
rcpt_ Receipt ID Identifier for a receipt.
re_ Refund ID Identifier for a Refund object.
req_ Request ID Identifier for a HTTP Request
rk_live_ Live restricted key Restricted key for live environment eg. stripe-cli
rk_test_ Test restricted key Restricted key for test environment eg. stripe-cli
seti_ Setup Intent ID Identifier for a Setup Intent object.
si_ Subscription Item ID Identifier for a Subscription Item object.
sk_live_ Live secret key Secret key in a live environment.
sk_test_ Test secret key Pecret key in a test environment.
sku_ SKU ID Identifier for a SKU object.
sli_ Subscription Line Item ID Identifier for a Subscription Line Item object.
sqr_ Scheduled Query Run ID Identifier for a Scheduled Query Run object.
src_ Source ID Identifier for a Source object.
src_ Source ID Identifier for a Source object.
sub_ Subscription ID Identifier for a Subscription object.
tml_ Terminal Location ID Identifier for a Terminal Location object.
tmr_ Terminal Reader ID Identifier for a Terminal Reader object.
tok_ Token ID Identifier for a Token object.
trr_ Transfer ID Identifier a Transfer object.
tu_ Topup ID Identifier for a Topup object.
txi_ Tax ID Identifier for a customer Tax object.
txn_ Transaction ID Identifier for a Transaction object.
txr_ Tax Rate ID Identifier for a Tax Rate object.
we_ Webhook Endpoint ID Identifier for a webhook endpoint.
whsec_ Webhook Secret Secret key for signing a web hook.
@arnebr
Copy link

arnebr commented Dec 22, 2021

Additional prefixes:

Prefix Description Notes
price_ Price ID Identifier for a Price object
req_ Request ID Identifier for a HTTP Request
qt_ Quote ID Identifier for a Quote object
whsec_ Webhook Secret Secret key for signing a web hook
rk_test_ Test restricted key Restricted key for test environment eg. stripe-cli
rk_live_ Live restricted key Restricted key for live environment eg. stripe-cli

Changelog
21/12/29 - Add qt_ prefix

@mixelpixel
Copy link

Thanks for this!

Do you know what the py_ prefix denotes?

I see it in the Payment Intent object {charges: {data: [{id: py_123ABCxyz}]}}

@fnky
Copy link
Author

fnky commented Feb 12, 2022

@mixelpixel That is a Payment ID (e.g. part of a charge). Will update the table to include it :)

EDIT: Updated to include the py_ and additional prefixes by @arnebr :-)

@arlyon
Copy link

arlyon commented Feb 15, 2022

I am working on arlyon/async-stripe and have a number on there (https://github.com/arlyon/async-stripe/blob/master/src/ids.rs) that are not on this list. To sort out the confusion, I have reached out to people at stripe who can hopefully provide / create a canonical list. Thanks for this! Will update with progress.

@mixelpixel
Copy link

mixelpixel commented Feb 15, 2022

thanks @fnky,

Seems to correlate to ach xfrs & ch to cards, e.g.

ch_-py_

@bal-jhand
Copy link

The prefix in my organisations Stripe Account for Dispute IDs seems to be du, not dp

Looking at our database I have noticed a change between the prefixes during 2019-2020.

Can someone else confirm this on their end?

@arlyon
Copy link

arlyon commented Mar 30, 2022

I am working on arlyon/async-stripe and have a number on there (https://github.com/arlyon/async-stripe/blob/master/src/ids.rs) that are not on this list. To sort out the confusion, I have reached out to people at stripe who can hopefully provide / create a canonical list. Thanks for this! Will update with progress.

Official answer from Stripe is there is no canonical list either internally or externally so this is as good as it gets!

@ixti
Copy link

ixti commented Apr 18, 2022

The prefix in my organisations Stripe Account for Dispute IDs seems to be du, not dp

Looking at our database I have noticed a change between the prefixes during 2019-2020.

Can someone else confirm this on their end?

Somehow stripe-cli (stripe trigger) testing tool is using dp_, while when disputes are coming from Stripe itself - they are du_.

@ixti
Copy link

ixti commented Apr 18, 2022

@bal-jhand I have a hunch that it might be related to what dispute was created against. When payment was made via old charge api, then it will be dp_, if using new payment intent api then du_. But I might be wrong. Just guessing here.

@btc
Copy link

btc commented May 12, 2022

Does anyone have a link to a resource that explains the design of and motivation for Stripe's ID format?

@fnky
Copy link
Author

fnky commented May 12, 2022

@btc Patrick Collison, co-founder and CEO of Stripe, wrote about this 9 years ago on Quora. It's to easily identify the types of IDs in logs and stacktraces.

@btc
Copy link

btc commented May 13, 2022

I'm curious:

  • what is the byte length?
  • what is the "base-N" encoding used?
  • are there any additional, interesting properties to note?

@fnky
Copy link
Author

fnky commented May 13, 2022

It's unlikely Stripe will provide any specific information. But my theory is that it's a combination of timestamp, random bits and maybe other internal-specific bits. It's likely encoded as base62 or some derivative thereof.

The number of bytes seem to vary depending on context, likely due to introducing random bits to avoid, some bits for cryptography (secret keys, tokens).

If you're interested in IDs with similar properties, there is a plethora. Just to name a few:

@allynsweet
Copy link

Found a new ID prefix when refunding a payment charge via ACH using API 2020-08-27: pyr_

{
  "id": "pyr_XXXXXXXXXXXXXXXX",
  "object": "refund",
  "amount": 322,
  "balance_transaction": "txn_XXXXXXXXXXXXXXXX",
  "charge": ["py_XXXXXXXXXXXXXXXX"],
  "created": 1661959715,
  "currency": "usd",
  "metadata": {},
  "payment_intent": ["pi_XXXXXXXXXXXXXXXX"],
  ...
}

I'm guessing the "r" at the end refers to a refund on a Payment (py) object.

@fnky
Copy link
Author

fnky commented Sep 2, 2022

@allynsweet Good catch. It seems indeed to be related to refunds of payments. It's more of a psuedo object, as in its object type is refund but the prefix is different from the typical re_.

@davidfilkins
Copy link

Are all Stripe IDs in the format {prefix}_{24 alphanumeric characters}?

@faridanthony
Copy link

Are all Stripe IDs in the format {prefix}_{24 alphanumeric characters}?

They use {prefix}_{ulid}. Read more here: https://blog.daveallie.com/ulid-primary-keys?utm_source=pocket_mylist

@turakvlad
Copy link

turakvlad commented Oct 20, 2022

I am not sure that Stripe uses {ulid}. At least the resources I was looking at do not use it. For example, we may have a customer's ID like this one cus_Mdww7G4vQHS464.Mdww7G4vQHS464 is not valid ULID.

@daiplusplus
Copy link

daiplusplus commented Oct 24, 2022

@davidfilkins Are all Stripe IDs in the format {prefix}_{24 alphanumeric characters}?

No:

Very old Stripe objects (prior to 2012) had "traditional UUIDs" as object-identifiers (according to this article by a Stripe employee) - so any active Stripe account today made prior to 2012 will have at least some prefix-less object-identifiers in it (as Stripe's object-identifiers are ostensibly immutable, so any object created before prefixes were added will retain its prefix-less object-id):

https://dev.to/stripe/designing-apis-for-humans-object-ids-3o5a

Stripe has been using this prefixing technique since 2012, and as far as I know, we’re the first ones to implement it at scale. [...] Before 2012, all Object IDs at Stripe looked more like traditional UUIDs. If you were an early Stripe adopter you might notice that your account ID still looks like this, without the prefix.

However, for all new Stripe objects since then they'll have the prefix. I didn't start using Stripe until around 2014 so I've never encountered a prefix-less object-id in my life - so given the benefits of performing method precondition assertions (i.e. parameter validation) I use this regex and it's never failed on valid input in the ~8 years I've been using it:^[a-z]{2,5}_[0-9A-Za-z]{8,58}$ (use with case-sensitive mode).

The {8,58} quantifier in my regex is nothing more than an educated hope that Stripe would never do something as silly as have an actual 256-char-long object-id value (despite their threats to do so...]) - as I've almost always defaulted to using varchar(64) for RDBMS columns for storing Stripe object-ids (using a low varchar max-length n value is important to constrain maximum row-size to avoid off-table string storage which really harms DB performance).

That said, in the past 8 years I've been using Stripe I've never encountered a Stripe object-id longer than 34 characters, including the type-prefix (excepting things like Hosted Invoice PDF URIs of the form live_[0-9A-Za-z]{100+} which tend to be around 100-102 chars long.... but also consider that in those 8 years I've never ventured beyond Stripe's Checkout/Customers/Products/Subscriptions/Payments/Invoices functionality; as I haven't touched the rest of Stripe's offerings and it's entirely possible that much longer object-ids exist there. YMMV etc.

https://stripe.com/docs/upgrades#what-changes-does-stripe-consider-to-be-backwards-compatible

Stripe considers the following changes to be backwards-compatible:
[...]
Changing the length or format of opaque strings, such as object IDs, error messages, and other human-readable strings.
[...]
You can safely assume object IDs we generate will never exceed 255 characters, but you should be able to handle IDs of up to that length.

...but given Stripe's consistent and clear-messaging to expect 255-char-long object-ids I think unless you have an overriding and compelling technical reason to restrict string-length to something shorter then you should stick with treating object-ids as purely opaque case-sensitive strings up-to-255 chars, and don't even attempt to regex-them or inspect their contents. I know I do in my own code, but it's me who will be suffering the consequences of my decision-making, not you.

There was actually a breaking-change in Stripe's API's December 2019 and May 20198 updates that wouldn't have affected people treating ids as opaque strings, but likely would have failed in my own code:

https://stripe.com/docs/upgrades#2019-12-03

  • The id field of all invoice line items have changed and are now prefixed with il_. The new id has consistent prefixes across all line items, is globally unique, and can be used for pagination.
  • You can no longer use the prefix of the id to determine the source of the line item. Instead use the type field for this purpose.

https://stripe.com/docs/upgrades#2018-05-21

  • The id field of invoice line items of type=subscription no longer can be interpreted as a subscription ID, but instead is a unique invoice line item ID.

...though curiously the same update does describe a constraint on the characters inside Coupon, SKU, Customer, Product, and Plan ids:

Coupon, SKU, customer, product and plan ids may only contain alphanumeric and _- characters on creation.

...curious. And no Stripe API updates since then have abrogated that point either.


@faridanthony They use {prefix}_{ulid}. Read more here: https://blog.daveallie.com/ulid-primary-keys?utm_source=pocket_mylist

That article summarizes ulid, but it doesn't claim that Stripe is using ulid. Indeed, @turakvlad is correct in that Stripe object-ids aren't ulids, simply because ulids are case-insensitive but Stripe object-ids are case-sensitive (so anyone who forgot to specify COLLATE <some-case-sensitive-collation>) in their CREATE TABLE statement is going to have problems...).


Another curious thing, is that Stripe's object-ids are also clearly not entirely random: there's definitely a time-component of some significance (or some other monotonic change) that I've observed in some ids, like evt_ ids for Stripe Event objects. Here's a screenshot of some logged Stripe events from one of my databases, showing how Events all have similar leading characters that seem to correspond to the date+time:

image

...so I assume that dev.to article's claims of being "random" represents a drastic over-simplification of whatever their real scheme is ...which could still be based on incrementing integer values in their underlying database (and consider that truly random primary-key values are a good way to wreck your INSERT performance and is why SQL Server prefers NEWSEQUENTIALID() instead of NEWID() if you're using a GUID/UUID as a PK).

@payellodevsupport
Copy link

There are a couple more which are not listed:

tcc_
This is referenced as a "connection_context_id" in the Terminal API

tmars_
This is referenced as a "reader_rpc_session_token" and a "sdk_rpc_session_token" in the Terminal API

pss_live_
This is referenced as a "stripe_session_token" in the Terminal API

finvp_ and binvp_
These are both used as fee IDs in a Payout Transaction breakdown. Can be found in the Dashboard API at dashboard.stripe.com/v1/transfers/po_XXXXXXX/transactions

@nestor-sk
Copy link

One more for the list sub_sched_ for subscription schedules

@dpaola2
Copy link

dpaola2 commented Jan 19, 2023

One more: ca_<foo> for stripe connect client_ids (for building the oauth redirect uri, amongst other things)

@garymoon
Copy link

garymoon commented Jan 31, 2023

Adding some associated dashboard URLs (the ID itself would be appended to the URL).

Prefix	Description	Notes	URL
ch_	Charge ID	Identifier for a Charge object.	https://dashboard.stripe.com/payments/
cus_	Customer ID	Identifier for a Customer object.	https://dashboard.stripe.com/customers/
il_	Invoice Line Item ID	Identifier for a Invoice Line Item object.	https://dashboard.stripe.com/subscriptions/
in_	Invoice ID	Identifier for an Invoice object.	https://dashboard.stripe.com/invoices/
pi_	Payment Intent ID	Identifier for a Payment Intent object.	https://dashboard.stripe.com/payments/
po_	Payout ID	Identifier for a Payout object.	https://dashboard.stripe.com/payouts/
price_	Price ID	Identifier for a Price object.	https://dashboard.stripe.com/prices/
prod_	Product ID	Identifier for a Product object.	https://dashboard.stripe.com/products/
promo_	Promo Code ID	Identifier for a promo/coupon code.	https://dashboard.stripe.com/promotion_codes/
seti_	Setup Intent ID	Identifier for a Setup Intent object.	https://dashboard.stripe.com/setup_intents/
sub_	Subscription ID	Identifier for a Subscription object.	https://dashboard.stripe.com/subscriptions/

@payellodevsupport
Copy link

Prefix	Description
ri_	return_intent
rist_	return_intent_secret_token
retatt_	return_attempt
retmst_	return_method_secret_token
retm_	return_method

@connorgurney
Copy link

You might find it helpful to know that em_ is used for emails sent out by Stripe.

@notpushkin
Copy link

notpushkin commented Aug 21, 2024

If you're interested in IDs with similar properties, there is a plethora.

There's also UUIDv7 now!

Shameless plug: I'm making a Python library to generate Stripe-like IDs, based on UUIDv7 and Crockford’s base32: https://pypi.org/project/prettyid/

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