Closed joshsmith closed 7 years ago
Some notes here:
Organization owner can create standalone account https://stripe.com/docs/connect/standalone-accounts
OAuth client_id and redirect_uri development client_id for testing
Connect button to authorize_url http://jsfiddle.net/luddep/vM7R7/
Handle connection or error authorization code or access denied make POST request to Stripe send more information to pre-fill fields https://stripe.com/docs/connect/reference#get-authorize-request Store all details from stripe on server
Create a $1 plan on the account
Set quantity higher to make it a larger plan This creates virtual plans We’ll want these to be fixed dollar amounts
Revoked access webhook needs handled
Customer objects get created and stored on platform account This is so we can reuse them across other things
Create subscriptions and plans on connected account and application fee on subscription payments Define application_fee_percent as integer between 1 and 100 (5, in our case)
https://github.com/ride/ember-stripe-service https://stripe.com/docs/subscriptions/guide https://stripe.com/docs/checklist https://github.com/NullVoxPopuli/aeonvera-ui/blob/58ffcb3500926a24ed68915ac4f7109869888d88/app/components/integrations/stripe/connect-button.js#L8 https://stripe.com/docs/subscriptions/guide#setting-quantities
Some UI:
stripe_user[url]
If you will be prefilling this field, we highly recommend that the linked page contain a minimum of a description of the user's products or services and contact information. If we don't have enough information, we'll have to reach out to the user directly before initiating payouts.
We'll need to find a way to add public contact information to a project's page for this purpose.
Looks like people accepting payments via Stripe will also have to be a business, so if they don't have one, we should recommend they go through Stripe Atlas to create an organization to start accepting those payments: https://stripe.com/atlas/faq#what-does-atlas-cost
EDIT: Actually, sole proprietor is not a formal entity. Just doing business as a person makes you one.
We'll probably want a URL like /webhooks/stripe
.
Webhook endpoints may occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making your event processing idempotent. One way of doing this is logging the events you've processed, and then not processing already-logged events.
We should therefore have a StripeEvent
model of some sort.
We could consider using https://github.com/gearnode/stripe_eventex for events/webhooks.
User goes to project page (Donations)
If no account, generate button to create one Stripe.Connect.generate_button_url(csrf_token)
If account, button to create new StripePlan
to start accepting money for this project
User clicks link
User enters Stripe details
User directed back to site (redirect_uri) w/ auth code or error
https://example.com/connect/default/oauth/test?scope=read_write&code=AUTHORIZATION_CODE
Stripe.Connect.oauth_token_callback code
%{
token_type: "bearer",
stripe_publishable_key: "PUBLISHABLE_KEY",
scope: "read_write",
livemode: false,
stripe_user_id: "USER_ID",
refresh_token: "REFRESH_TOKEN",
access_token: "ACCESS_TOKEN"
}
Store tokens in StripeAccount
for Organization
Create Stripe Plan for that standalone account for each project the organization has (store as StripePlan
) ...(need to also ensure new StripePlan
is created any time a new project is created for an organization with a standalone account)
Check if account is verified (what webhook?)
Payments are enabled now!
User decides to donate
Collect card details
Create token with Stripe.js
Submit token to server w/ amount
Create subscription in connected account: create(customer_id, opts, key)
where key
is the standalone account API key
application_fee_percent 5
Create customer if they don’t exist and subscribe them to the new plan
Store customer details on server (StripeCustomer
)
Store donation details on server
Listen for webhook events
For platforms, we’ve learned that proactively emailing users about the following is helpful:
We could actually allow cents, too. Not hard to do. We'll just have $0.01
subscriptions and change the amount there.
Not sure best way to handle on front-end or validate on backend.
Card brand can be Visa
, American Express
, MasterCard
, Discover
, JCB
, Diners Club
, or Unknown
.
I think we want to handle the following events:
account.updated
describes an account
Occurs whenever an account status or property has changed.
account.application.deauthorized
describes an application
Occurs whenever a user deauthorizes an application. Sent to the related application only.
child parameters
account.external_account.created
describes an external account (e.g., card or bank account)
Occurs whenever an external account is created.
account.external_account.deleted
describes an external account (e.g., card or bank account)
Occurs whenever an external account is deleted.
account.external_account.updated
describes an external account (e.g., card or bank account)
Occurs whenever an external account is updated.
application_fee.created
describes an application fee
Occurs whenever an application fee is created on a charge.
application_fee.refunded
describes an application fee
Occurs whenever an application fee is refunded, whether from refunding a charge or from refunding the application fee directly, including partial refunds.
application_fee.refund.updated
describes a fee refund
Occurs whenever an application fee refund is updated.
charge.failed
describes a charge
Occurs whenever a failed charge attempt occurs.
charge.refunded
describes a charge
Occurs whenever a charge is refunded, including partial refunds.
charge.succeeded
describes a charge
Occurs whenever a new charge is created and is successful.
charge.updated
describes a charge
Occurs whenever a charge description or metadata is updated.
customer.created
describes a customer
Occurs whenever a new customer is created.
customer.deleted
describes a customer
Occurs whenever a customer is deleted.
customer.updated
describes a customer
Occurs whenever any property of a customer changes.
customer.source.created
describes a source (e.g., card or Bitcoin receiver)
Occurs whenever a new source is created for the customer.
customer.source.deleted
describes a source (e.g., card or Bitcoin receiver)
Occurs whenever a source is removed from a customer.
customer.source.updated
describes a source (e.g., card or Bitcoin receiver)
Occurs whenever a source's details are changed.
customer.subscription.created
describes a subscription
Occurs whenever a customer with no subscription is signed up for a plan.
customer.subscription.deleted
describes a subscription
Occurs whenever a customer ends their subscription.
customer.subscription.updated
describes a subscription
Occurs whenever a subscription changes. Examples would include switching from one plan to another, or switching status from trial to active.
invoice.created
describes an invoice
Occurs whenever a new invoice is created. If you are using webhooks, Stripe will wait one hour after they have all succeeded to attempt to pay the invoice; the only exception here is on the first invoice, which gets created and paid immediately when you subscribe a customer to a plan. If your webhooks do not all respond successfully, Stripe will continue retrying the webhooks every hour and will not attempt to pay the invoice. After 3 days, Stripe will attempt to pay the invoice regardless of whether or not your webhooks have succeeded. See how to respond to a webhook.
invoice.payment_failed
describes an invoice
Occurs whenever an invoice attempts to be paid, and the payment fails. This can occur either due to a declined payment, or because the customer has no active card. A particular case of note is that if a customer with no active card reaches the end of its free trial, an invoice.payment_failed notification will occur.
invoice.payment_succeeded
describes an invoice
Occurs whenever an invoice attempts to be paid, and the payment succeeds.
invoice.updated
describes an invoice
Occurs whenever an invoice changes (for example, the amount could change).
plan.created
describes a plan
Occurs whenever a plan is created.
plan.deleted
describes a plan
Occurs whenever a plan is deleted.
plan.updated
describes a plan
Occurs whenever a plan is updated.
source.canceled
describes a source (e.g., card or Bitcoin receiver)
Occurs whenever a source is canceled.
source.chargeable
describes a source (e.g., card or Bitcoin receiver)
Occurs whenever a source transitions to chargeable.
source.failed
describes a source (e.g., card or Bitcoin receiver)
Occurs whenever a source is failed.
transfer.created
describes a transfer
Occurs whenever a new transfer is created.
transfer.failed
describes a transfer
Occurs whenever Stripe attempts to send a transfer and that transfer fails.
transfer.paid
describes a transfer
Occurs whenever a sent transfer is expected to be available in the destination bank account. If the transfer failed, a transfer.failed webhook will additionally be sent at a later time. Note to Connect users: this event is only created for transfers from your connected Stripe accounts to their bank accounts, not for transfers to the connected accounts themselves.
transfer.reversed
describes a transfer
Occurs whenever a transfer is reversed, including partial reversals.
transfer.updated
describes a transfer
Occurs whenever the description or metadata of a transfer is updated.
The events above imply models for:
StripeAccount
- describes standalone account on our platformStripeApplicationFee
- fee paid to code corpsStripeCard
- card on a customer's accountStripeCharge
- charge event on a customer's cardStripeEvent
- event, needs to be tracked to be sure other data is updatedStripeInvoice
- invoice for some chargeStripePlatformCustomer
- customer for the platform (to be copied to the connect account)StripeConnectCustomer
- customer for the standalone accountStripePlan
- plan for a connected accountStripeSubscription
- subscription for a connected accountStripeTransfer
- transfers to us, transfers to connected accountsProcess for copying a customer on the platform to a customer on a connected account:
Collect a token using your main account's publishable API key.
Consume the token with your main account's secret API key to save the payment information as a customer object.
For each connected account that would like to use the stored payment information, create a token referencing the main account's customer ID. The customer object can only be copied using the connected account's access token.
Now that you have a fresh token, use your connected account's access token to either create a charge or create a customer object. This will create an entirely new object (i.e., has its own ID) in the connected account.
https://support.stripe.com/questions/connect-publishable-key-error-with-shared-customers
Accept donations from project page (as organization owner) Add Stripe if not exists (Stripe button) Otherwise click to add donations Redirect to Stripe UI Come back, present waiting screen until Stripe accepts Send email once Stripe accepts Create goals (must have at least one to start accepting donations) Able to edit goals Allow project to start accepting donations (create plan) Have link for people to start donating (to project page)
See project page (total amount) Click amount or enter some Click continue => new page Edit to update amount if needed Enter credit card information or use existing card Submit form to charge card Get success screen (should be happy!) with link to share to others to donate (and social buttons?) Click to return to project Show your contribution amount instead of donate buttons (with a thanks!)
(Things in italics can maybe wait)
User account page Edit card information See list of all your donations
Project donations page See list of all transfer amounts
It honestly all looks really good and thorough. The only thing I'm concerned about, but I also assume you did more research in that area than I did, is if we're losing on donations by going recurring-only.
Are the pros of us going recurring donations only outweighing the cons?
Also, regarding cents, I really don't think that's necessary, but it's good to know that we can do it.
@begedin I think we can go back and add single donations later. For now it's better to do recurring I think and just focus on that.
Closing this because we're pretty out of sync with what has been discussed so far.
Here's how we want to structure this:
Donation
will be monthly recurring.Customer
object on the platform account for later reuse.