Payment Security on Cyca: Architecture, Encryption, and the Choice of Stripe
A payment system is judged by what happens when something goes wrong: a breached server, a stolen phone, a request forged by someone who should not have access. Intentions do not decide those outcomes. Architecture does, because it determines in advance what a failure is able to expose. This post sets out how payments on Cyca are built, and the reasoning behind each decision.
The principle: the card number never reaches Cyca
The most reliable way to protect sensitive data is not to hold it. When a person adds a card on Cyca, the number, expiry date and security code are entered into Stripe's own payment form, running inside the app, and sent from there directly to Stripe. They do not pass through Cyca's servers and are not written to our database. There is no function anywhere in our system that accepts a card number. That is a design rule, not an accident, and it is written into the code as one.
The server's part is narrower. It asks Stripe for three short-lived credentials the form needs in order to work: a reference to the person's customer record at Stripe, a temporary key limited to that record, and a one-time secret for the single act of saving a card. It passes them to the app and steps aside. Once the card is saved, what Cyca reads back is limited to what a person needs to recognise their own card: the brand, the last four digits and the expiry date.
Encryption and tokenisation
Card details are encrypted in transit from the phone to Stripe, and stored by Stripe under PCI DSS Level 1, the most stringent level of certification in the payment card industry, assessed independently every year. In place of the card, Cyca holds a token: an identifier that refers to the card inside Stripe and means nothing anywhere else. A token cannot be turned back into a card number, and it cannot be used outside the Stripe account that issued it. If our database were copied in full, it would contain no card numbers, because none were ever there.
When a card's issuing bank asks the cardholder to confirm the card, that exchange also takes place between the person, their bank and Stripe. Cyca is told the result, not the details.
Privacy: collecting less
Privacy in payments is usually discussed as a question of how data is protected. The earlier question is how much data exists at all. When Cyca creates a person's record at Stripe, it sends one thing: an internal reference that lets the two records find each other. It does not send a name, an email address or a phone number. On our side, the link between a Cyca account and its Stripe record is a single row.
That row is part of each person's data file, like everything else we hold about them. A request to export your data includes it. A request to erase your data deletes the customer record at Stripe itself, and every card attached to it, rather than hiding it from view in our app.
Authority: every action is checked with Stripe
A saved card is referred to by an identifier, and identifiers travel between the phone and the server. A system that trusted them could be led to act on a card belonging to someone else, simply by being sent a different identifier. Cyca does not trust them. Before a card is made the default or removed, the server asks Stripe directly whether that card belongs to the person making the request, and acts only if Stripe confirms it. The answer comes from Stripe, not from anything the phone has said.
The same care applies to smaller details. Cyca speaks to one fixed version of Stripe's interface, so behaviour cannot change underneath us without a deliberate decision. Records made in Stripe's test environment are never accepted in the live one, or the other way round. And the form accepts cards only, because a payment method the app cannot display is one a person cannot see or remove.
Why an established processor
Building a payment processor is possible, and for some companies justified. For a platform whose purpose is commerce rather than payment processing, it would mean carrying the whole burden of card security (certification, audits, fraud detection, relationships with card networks and banks) in exchange for control we have no use for. The more responsible choice is to place the most sensitive part of the system with an organisation whose sole business it is, and which is held to the industry's highest standard every year.
Familiarity matters too, for a practical reason. Stripe handles payments for a great many of the businesses people already buy from online, and the form a person sees when adding a card to Cyca follows conventions they have met many times before, drawn in Cyca's own colours. People hesitate, correctly, at payment forms they do not recognise. Convenience follows from the same design: a card saved once is available again without being typed again.
What is built, and what follows
This work is being done in stages, and each stage is tested before the next begins. The first, saving and removing cards and choosing a default, is built. The second is paying shops: each seller will complete a one-time payout setup with Stripe, and their earnings will be paid to their bank. The third is paying at checkout, including Apple Pay, with refunds tied to the same record as the original payment.
The principle does not change from one stage to the next. Card details stay with Stripe, and Cyca holds only what it needs in order to know that a payment took place.