Repository: gratipay/gratipay.com

Issue:
Clarify team application process and parameters on application page
Reticketed from https://github.com/gratipay/applications/issues/17#issuecomment-129905354, which I think is a great, civil discussion about how the team application process is perceived and fuzzy and open to misunderstanding.

In particular, 
- team application guidelines should be spelled out explicitly on the [team application page](https://gratipay.com/new), and
- legal reasons behind requiring applications should be explained in the site documentation, not solely on blog posts.

I ask that discussion of the application policies be kept in a separate ticket at [inside.gratipay.com](https://github.com/gratipay/inside.gratipay.com/issues?utf8=%E2%9C%93&q=is%3Aissue++sort%3Aupdated-desc+) and this ticket be retained for implementation or rejection of this change.  Hopefully this will avoid confusing the two subjects.



Discussion:
Some thoughts on text.

> This application is only required if you want to receive money.  You can give to existing teams without creating your own team.
> 
> Applications are now required for teams to receive money due to U.S. financial regulations about money transmission.  You can read more about this here [and that link should go to real documentation, not a GitHub issue].

^This is important.  People are confused about _why_: https://github.com/gratipay/applications/issues/11#issuecomment-130436584

> Your application will be reviewed at [applications queue] and you will receive an email confirming receipt.  The following criteria will be used to accept or reject your application:
> - a
> - b
> - c

Copying from [Gratipay 2.0](https://medium.com/gratipay-blog/gratipay-2-0-2453d3c53077) to have here:

> Furthermore, we’ve implemented an application and approval process for new teams on Gratipay. We want the teams receiving money on Gratipay to understand our [mission](http://inside.gratipay.com/big-picture/mission) and our [brand values](http://inside.gratipay.com/big-picture/brand/), and to be on board with the concept of open work. Therefore, our application asks these four questions:
> - What product or service does your team provide?
> - What is your revenue model?
> - How can other people get involved with your team?
> - How do you share revenue with contributors?

Clearly, mission and brand values have been treated as guidelines in the past, but the present application process treats them as rules to be applied to applicant teams.  

The mission and brand values pages, if part of the application process, need to be on the main Gratipay website, _not_ just inside.gratipay.com.

http://inside.gratipay.com/big-picture/mission
http://inside.gratipay.com/big-picture/brand/

A how-to page about reviewing team applications should be created at http://inside.gratipay.com/.

Aha!  Here is a draft of possible criteria from May 9: https://github.com/gratipay/gratipay.com/issues/3390#issuecomment-100511894

And here is how they are stated in the [TOS](https://gratipay.com/about/policies/terms-of-service):

> '4. Rules for Gratipay Teams
> - Teams may accept payments on the Service only for Open Work, meaning that they provide a clear path for any individual to voluntarily begin contributing to the Team's work, and to share in any revenue the Team generates.
> - A Team can only begin receiving payments from Participants once it has provided a working withdrawal mechanism for receiving payments (e.g. bank account information).
> - Teams and their Open Work must be consistent with Gratipay's Brand Guidelines and Acceptable Use Policy.
> - Gratipay reserves the right to reject, suspend, or remove a Team at any time, and for any reason.
> - Establishing a Team on Gratipay involves an application and approval process. As part of this process, the Gratipay community will have the opportunity to publicly evaluate and provide commentary about the Team. However, all decisions regarding whether to accept, reject, suspend, remove, or take any other action regarding a Team belong solely to Gratipay.

We're in the process of [revising the team application](https://github.com/gratipay/gratipay.com/issues/3679), so the questions listed above may change.

Folding in discussion from #3679 ...

> Now that we have received 79 applications, let's think about some tweaks to the application to make sure it's doing what we want.
> 
> I think the **product or service** question is pretty straightforward and I think it's fine.
> 
> **Revenue model** tends to see these three responses:
> - "We ask people for money."
> - "~~We have no revenue model.~~" "I either don't grasp, or willfully reject, the concept of a revenue model."
> - @wout's [answer](https://github.com/gratipay/applications/issues/15) :)
> 
> This question is controversial, but I think that means it's working as intended. The point of this question is to filter out people who are thinking in terms of building a viable open business from those who aren't.
> 
> For **Contributing** I think we can drop back from an open-ended textarea to a link to contributor documentation or at least an issue tracker. We should specify that this is where we expect to find a list of available open work that's ready to start without having to explicitly apply first.
> 
> **Paying contributors** really comes down to "kids eat first" or "parents eat first." I think we should allow both when we bring back payroll (#3433), and this part of the application will simply be a select between those two options. One pattern we're seeing is that nobody is making any revenue, so they aren't at a place where they can really think about sharing it. They're reluctant to make promises to share revenue when they themselves are not receiving enough yet. I think we want to keep "everyone sets their own take" but allow for "parents eat first."

@mattbk at https://github.com/gratipay/gratipay.com/issues/3679#issuecomment-130692903:

> > The point of this question is to filter out people who are thinking in terms of building a viable open business from those who aren't.
> 
> This implies that you only want people who have any sort of business sense and are focused on that area rather than doing whatever it is that they do.  If the goal of Gratipay is to help push open projects (meaning minimum barrier to contribution), why are we setting a barrier to entry of "treating this project as a moneymaking endeavor"?
> 
> That's not to say we shouldn't ask about revenue model, but maybe it should be phrased in such a way as "Many teams currently have no revenue stream.  If your team started generating revenue through Gratipay, how would you spend it?"  _But_ what is the answer that "fits" with Gratipay's mission and brand guidelines?
> 
> **Contributing** looks good, and I think the criteria of "Does this team have a well-documented method for new people to contribute" is _much_ stronger for accept/close team choices.  
> 
> (The [TechRaptor model](https://github.com/gratipay/applications/issues/17) of "Send us your contribution and we'll decide whether it fits" is, IMHO, within the bounds of Gratipay in the same way I can submit a PR to any project on GitHub--although not all GitHub projects have documentation explaining how people can get involved.)

> "Many teams currently have no revenue stream. If your team started generating revenue through Gratipay, how would you spend it?"

This makes the same fundamental mistake that's behind the "We have no revenue model" sort of answers. A [revenue model](https://en.wikipedia.org/wiki/Revenue_model) is not how you would _spend_ money, it's how you want to _make_ money. It's a plan for _income_, not for _expenses_.

> A **revenue model** is a framework for generating revenues. It identifies which revenue source to pursue, what value to offer, how to price the value, and who pays for the value. It is a key component of a company's business model. It primarily identifies what product or service will be created in order to generate revenues and the ways in which the product or service will be sold.
> 
> Without a well defined revenue model, that is, a clear plan of how to generate revenues, new businesses will more likely struggle due to costs which they will not be able to sustain. By having a clear revenue model, a business can focus on a target audience, fund development plans for a product or service, establish marketing plans, begin a line of credit and raise capital.

We absolutely want people who understand what a revenue model is at the helm of the teams on Gratipay, because we want the teams on Gratipay to be _viable_, and they can't be without "a clear plan of how to generate revenues."

Now, one problem with the revenue model question as it stands is that Gratipay only really supports one model: **[voluntary](https://en.wikipedia.org/wiki/Pay_what_you_want) [subscriptions](https://en.wikipedia.org/wiki/Subscription_business_model)** (hence the first class of answers, "We ask people for money"). What if we changed this to something like:

> Please describe the revenue model that Gratipay supports.

Or:

> Gratipay implements the voluntary subscription revenue model. What does that mean to you?

Or even:

> What is your business plan?

Understood on the explanation of revenue model.

The second or third wording make sense.  The first is either a gimme or a gotcha, which makes it meaningless as team approval criteria (and especially meaningless on a team description profile).

"Gratipay teams must publicly state revenue sources" is one of those TOS-y statements that could be easily translated to the team application/team profile.

> [Y]ou only want people who have any sort of business sense and are focused on that area rather than doing whatever it is that they do.

Substitute "as well as" for "rather than" and you've nailed it.

![screen shot 2015-08-13 at 1 46 29 pm](https://cloud.githubusercontent.com/assets/134455/9257103/c12b6cbc-41c1-11e5-9f89-5e9dde21166b.png)

[We are building viable open businesses. We are building viable open businesses. We are building viable open businesses.](https://github.com/gratipay/applications/issues/11#issuecomment-130508673)

> The first is either a gimme or a gotcha, which makes it meaningless as team approval criteria (and especially meaningless on a team description page).

True.

> The second or third wording make sense. 

What if we combine them?

> Gratipay implements a [voluntary](https://en.wikipedia.org/wiki/Pay_what_you_want) [subscription](https://en.wikipedia.org/wiki/Subscription_business_model) [revenue model](https://en.wikipedia.org/wiki/Revenue_model). How does that fit into your business plan?

> I ask that discussion of the application policies be kept in a separate ticket at inside.gratipay.com and this ticket be retained for implementation or rejection of this change. Hopefully this will avoid confusing the two subjects.

P.S. I seem to have violated this, sorry. :-( 

Are we okay to continue here? We'll have a PR separate from this to track the implementation details.

> Are we okay to continue here?

The scope of the ticket has changed anyway, so it's fine with me.

> Gratipay implements a voluntary subscription revenue model. How does that fit into your business plan?

I like that one.

> Substitute "as well as" for "rather than" and you've nailed it.

I don't think Gratipay needs to be all things to all people, but the more we can help people grok business, the better.  So the open-cum-business explanation has to be clear at the outset (front of the website) rather than brought up after an application is submitted, because it's a big shift
from the gittip model, where any money made here was a [bonus](https://github.com/gratipay/applications/issues/11#issuecomment-130494815), not a path toward growing real revenue.

We believe teams can use openness to grow revenue, and we want teams to believe it too.  That's why we ask this question.

Now.

None of these questions addresses those nebulous items of "matching the mission and brand values/guidelines of Gratipay", except maybe the product or service question.
- How do we explain what this means on the team application page?
- How do we explain what this means to contributors who are reviewing teams?
- If assessment of a team includes detailed inquiry into what that team is doing in their own space/website, how will it be possible to keep up?  In the interest of applying our hopes of growth/revenue for teams to Gratipay itself, say we get 10 teams applying every day.  That's 70 teams to review every week.  Are we seriously opening ourselves up to reviewing 70 teams a
  week in more detail than is provided on the application itself?  tl;dr: "does it scale?"

> The scope of the ticket has changed anyway, so it's fine with me.

Okay, sorry.

> I like that one.

One issue: it brings back that word, "subscriptions," that we moved away from in https://github.com/gratipay/inside.gratipay.com/issues/117.

> the more we can help people grok business, the better.

Agreed. See also: #1273.

We're working with concepts that don't have good names yet.  Subscription implies a set reciprocity you receive.  

"Gratipay implements a voluntary recurring revenue model. How does that fit into your business plan?" ?

voluntary = "[good until canceled](http://www.inc.com/jim-schleckser/not-all-revenue-is-equal-the-5-best-kinds-of-recurring-revenue.html)" (GIC implies subscription, though)
recurring = self-explanatory?
revenue = money

Or in simple words:
"Gratipay lets people voluntarily give money to your team every week.  How does that fit into your business plan?"

> We're working with concepts that don't have good names yet.

Indeed.

> Subscription implies a set reciprocity you receive.

Well, but you _do_ receive a more or less set reciprocity. It's just that you receive it (at least conceptually) _before_ you pay instead of after.

> Gratipay implements a voluntary recurring revenue model.

I kind of like the idea of linking out to Wikipedia to explain these concepts. Would we still link "recurring" to https://en.wikipedia.org/wiki/Subscription_business_model?

The space we're trying to stake out is between "business" and "charity"—but more on the business side with charity tacked on.

Also, how do we handle the existing answers? I think we basically throw away the revenue model question for existing teams, and leave the new "How do we fit into your business plan?" question empty for them.

> Well, but you do receive a more or less set reciprocity. It's just that you receive it (at least conceptually) before you pay instead of after.

I _know_ there is an explicit description of why "gifts without reasons" is illegal, but https://github.com/gratipay/inside.gratipay.com/issues/201 is as close as I can find right now.  IIRC, that's why we ended up with team applications: to establish that everyone receiving money is doing so in exchange for providing measurable value.  Any idea what ticket that was?  I mentioned this at https://github.com/gratipay/gratipay.com/issues/3677#issue-100370479.

> Also, how do we handle the existing answers? I think we basically throw away the revenue model question for existing teams, and leave the new "How do we fit into your business plan?" question empty for them.

Keep the existing answer and add a line at the top of each response about the change in nomenclature.  That should serve as a placeholder until https://github.com/gratipay/gratipay.com/issues/3545 happens.

> Or in simple words

I like using well-defined names like "subscription model." We've established that we have a problem with lack of clarity on our site. If we can link out to a Wikipedia article or two then that takes some of the pressure off us to explain everything ourselves.

> I _know_ there is an explicit description of why "gifts without reasons" is illegal

201 has the [diagram](https://github.com/gratipay/inside.gratipay.com/issues/201#issuecomment-111157623), and here's the [prose](https://github.com/gratipay/inside.gratipay.com/issues/192#issuecomment-100048271). There's also "[Gratipay's Position in the AML Regulatory Environment](https://github.com/gratipay/inside.gratipay.com/issues/119#issuecomment-107081615)."

Thanks.  That's a lot to pare down, but it's a start.

> I don't think Gratipay needs to be all things to all people

Inspired by https://github.com/gratipay/applications/issues/33, what about something like this instead?

> What is your definition of success for your product or service? How does Gratipay fit into your plans?

+1 from https://twitter.com/AndyG244/status/631594026295259136

> What is your definition of success for your product or service? How does Gratipay fit into your plans?

That's a very vague question if it's supposed to be asking about a business model.

> I like using well-defined names like "subscription model." We've established that we have a problem with lack of clarity on our site. If we can link out to a Wikipedia article or two then that takes some of the pressure off us to explain everything ourselves.

We can use "subscription," I don't have a problem with that link.

> Gratipay implements a voluntary subscription revenue model. How does that fit into your business plan?

> That's a very vague question if it's supposed to be asking about a business model.

@mattbk Yeah, I'm chewing over here on the question of how tightly to draw the line on businesses vs. hobby projects on Gratipay. It seems that the pipeline of "viable (open) businesses" has "side projects" as its upstream. We may risk choking off the flow of viable businesses if we don't allow side projects. But then what's the path from side project on Gratipay to viable business? This gets into the "how formal of a company do I have to be?" sort of questions from https://github.com/gratipay/inside.gratipay.com/issues/242 and especially https://github.com/gratipay/gratipay.com/issues/3556#issuecomment-126561186.

I mean, I never had a business plan when I started Gratipay/Gittip. I didn't have a good answer to "What is your revenue model?" I threw something at the wall and it was kinda sticky so we started to figure it out with a lot of bumps and bruises. It seems that we would want people to be able to put a side project out on Gratipay and see if it gets any traction as a way to decide whether to invest even more time and energy into it.

> What is your definition of success for your product or service? How does Gratipay fit into your plans?

Here's the range of answers I would anticipate:
1. ambitious—"I want to be the next Microinstabookle."
2. small business—"[[W]e all want our OSS projects to be entirely self-sustaining entities that we make our living on.](https://github.com/gratipay/applications/issues/11#issuecomment-130494815)"
3. side project—"[If that time comes, it would be a good problem to have.](https://github.com/gratipay/inside.gratipay.com/issues/208#issuecomment-123927113)"
4. toy—"[I’m making small toys alone.](https://github.com/gratipay/applications/issues/33#issuecomment-130894202)"

I think (4) is not a good fit for Gratipay, because we want teams to provide open work. I think the rest fit, though (2) can probably benefit from some coaching (https://github.com/gratipay/gratipay.com/issues/1273), and for (3) we need to sort out the legal structure and the transition to (2) question.

If the main goal of Gratipay is to encourage open work--and provide a platform for generating revenue for that open work--then the open work question is more important than the revenue question.  I completely agree that side projects have their place.  Dealing with revenue generated through Gratipay _is_ a good problem to have, and something people should plan for--but is having that plan in place necessary for a team to start working?  I would argue not.

It seems to me that the focus of the application could be
- how is your work open?
- how do you pay the people doing the open work?

"How does Gratipay fit into your revenue model?" might not be necessary at all, because it's obvious how it fits in, because they're applying for a team at Gratipay.  Unless you want it as a survey question to determine how much impact Gratipay is having.

It just seems much more clear-cut to focus on (in parallel to the questions above)
- whether the team is providing something of real value that is open work
- whether the payroll is being used for that open work

(There's a whole topic of what to do when people lie, but that's covered at http://inside.gratipay.com/howto/handle-terms-violations.)

[This](https://github.com/gratipay/gratipay.com/pull/3568#issuecomment-113349074) needs to be stated as well:

> We'll just have it as our policy that a Review ticket must be open at least seven days before it can be decided upon.

> [T]he open work question is more important than the revenue question.

Agreed. Let's think about ditching the revenue question entirely, then, and reworking the "payroll" question to be more pointed. This will get at the heart of the matter: is a team owner ready to take on the additional responsibility of having employees and/or co-owners, per @stevepiercy at https://github.com/gratipay/gratipay.com/issues/3539#issuecomment-123921581:

> For the purposes of this draft, and for those who wish to become Team Owners, I think it is important to emphasize section 5.iii in the new terms. Assuming the role of Team Owner has greater responsibility and more duties than an ordinary User, and constitutes a significant change from the ordinary User perspective. Currently the draft has no mention of tax or other additional responsibility for this role. Thanks for your consideration.

Moreoever, I think we actually want to _require_ teams to use the Gratipay payroll feature; as of #3686 we're now saying as much (emphasis added):

> Basically you need to have a public issue tracker with documentation for self-onboarding, **and be willing to use our payroll feature once we bring it back**.

The reason why teams should be required to use Gratipay payroll is to provide a consistent experience for individuals looking for work on Gratipay. As an individual approaching Gratipay looking for work, I should be able to treat the list of teams on Gratipay as a catalog of available work opportunities.

Now, I _do_ think we should add some configurability to payroll, in particular, "parents eat first" in addition to "kids eat first." This could be the basis for a more pointed question on the Team application:

> When we bring back [payroll](), which distribution method do you want to use?
> - [ ] kids-eat-first
> - [ ] parents-eat-first

"Payroll" would link out to our explanation of the feature, to include descriptions of both distribution strategies. I'm thinking we'd make the question required but not have a default, as a way to encourage applicants to really engage the question and try to understand what we're asking them. This is really the point at which we get complicated because it's central to what we're doing, and we need people to stop and think about it.

> Now.
> 
> None of these questions addresses those nebulous items of "matching the mission and brand values/guidelines of Gratipay", except maybe the product or service question.

Right. I don't think of the application form questions as relating to the mission/brand fit question. That determination is made on the basis of the Team's existing brand presence as independently discoverable on the Internet. On this point, we're not interested in what they say about themselves: we're going to make our own investigation.

Okay, will pick up if needed at https://github.com/gratipay/inside.gratipay.com/issues/311,

_Although_ it should be clear somewhere that this is happening.

> Although it should be clear somewhere that this is happening.

How about if we link to the (soon-to-be-written) howto from the Team application, and then spell it out in detail on the "Application received" page under #3568?

> This could be the basis for a more pointed question on the Team application:

In writing up a new Payroll page on #3687 (https://github.com/gratipay/gratipay.com/commit/38d3c7f37641fabcd9929e6a45cb1366283ec3f3), I found myself not wanting to promise too much about the final shape of the payroll feature once we bring it back. How about something like this instead?

> By applying for a new Team, you're committing to use our [payroll]() feature once we [bring it back](). How do you feel about that?
> - [ ] excited
> - [ ] interested
> - [ ] wary, but open to it
> - [ ] not interested

If the user selects "not interested" we would say, "Sorry, we don't want your application."

Both of those payroll links go to this ticket, is that intended?  I imagine the first will go to the rewritten Payroll page and the second to the ticket.

That looks good to me.  It also makes it very transparent to potential contributors, which is nice.

> How about if we link to the (soon-to-be-written) howto from the Team application, and then spell it out in detail on the "Application received" page under #3568?

Perfect.

> Both of those payroll links go to this ticket, is that intended? I imagine the first will go to the rewritten Payroll page and the second to the ticket.

Yeah, sorry. Placeholder links.

Okay! I think we're about ready for a PR here. :-)


Resolving patch:
diff --git a/gratipay/models/team.py b/gratipay/models/team.py
--- a/gratipay/models/team.py
+++ b/gratipay/models/team.py
@@ -54,11 +54,10 @@ def insert(cls, owner, **fields):
 
             INSERT INTO teams
                         (slug, slug_lower, name, homepage,
-                         product_or_service, revenue_model, getting_involved, getting_paid,
+                         product_or_service, todo_url, onboarding_url,
                          owner)
                  VALUES (%(slug)s, %(slug_lower)s, %(name)s, %(homepage)s,
-                         %(product_or_service)s, %(revenue_model)s, %(getting_involved)s,
-                            %(getting_paid)s,
+                         %(product_or_service)s, %(todo_url)s, %(onboarding_url)s,
                          %(owner)s)
               RETURNING teams.*::teams
 
diff --git a/gratipay/utils/fake_data.py b/gratipay/utils/fake_data.py
--- a/gratipay/utils/fake_data.py
+++ b/gratipay/utils/fake_data.py
@@ -86,15 +86,16 @@ def fake_team(db, teamowner):
     try:
         #using community.slugize
         teamslug = community.slugize(teamslugname)
+        homepage = 'http://www.example.org/' + fake_text_id(3)
         _fake_thing( db
                    , "teams"
                    , slug=teamslug
                    , slug_lower=teamslug.lower()
                    , name=teamname
-                   , homepage='www.example.org/' + fake_text_id(3)
+                   , homepage=homepage
                    , product_or_service=random.sample(productorservice,1)[0]
-                   , getting_involved='build'
-                   , getting_paid='paypal'
+                   , todo_url=homepage + '/tickets'
+                   , onboarding_url=homepage + '/contributing'
                    , owner=teamowner.username
                    , is_approved=random.sample(isapproved,1)[0]
                    , receiving=0.1


Test patch:
diff --git a/gratipay/testing/__init__.py b/gratipay/testing/__init__.py
--- a/gratipay/testing/__init__.py
+++ b/gratipay/testing/__init__.py
@@ -170,11 +170,10 @@ def make_team(self, *a, **kw):
 
         team = self.db.one("""
             INSERT INTO teams
-                        (slug, slug_lower, name, homepage, product_or_service,
-                         getting_involved, getting_paid, owner, is_approved)
-                 VALUES (%(slug)s, %(slug_lower)s, %(name)s, %(homepage)s,
-                         %(product_or_service)s, %(getting_involved)s, %(getting_paid)s,
-                         %(owner)s, %(is_approved)s)
+                        (slug, slug_lower, name, homepage, product_or_service, todo_url,
+                         onboarding_url, owner, is_approved)
+                 VALUES (%(slug)s, %(slug_lower)s, %(name)s, %(homepage)s, %(product_or_service)s,
+                         %(todo_url)s, %(onboarding_url)s, %(owner)s, %(is_approved)s)
               RETURNING teams.*::teams
         """, _kw)
 
diff --git a/tests/py/test_teams.py b/tests/py/test_teams.py
--- a/tests/py/test_teams.py
+++ b/tests/py/test_teams.py
@@ -10,12 +10,13 @@ class TestTeams(Harness):
 
     valid_data = {
         'name': 'Gratiteam',
+        'product_or_service': 'We make widgets.',
         'homepage': 'http://gratipay.com/',
+        'onboarding_url': 'http://inside.gratipay.com/',
+        'todo_url': 'https://github.com/gratipay',
+        'agree_public': 'true',
+        'agree_payroll': 'true',
         'agree_terms': 'true',
-        'product_or_service': 'We make widgets.',
-        'revenue_model': 'People pay us.',
-        'getting_involved': 'People do stuff.',
-        'getting_paid': 'We pay people.'
     }
 
     def post_new(self, data, auth_as='alice', expected=200):
@@ -53,9 +54,8 @@ def test_all_fields_persist(self):
         assert team.name == 'Gratiteam'
         assert team.homepage == 'http://gratipay.com/'
         assert team.product_or_service == 'We make widgets.'
-        assert team.revenue_model == 'People pay us.'
-        assert team.getting_involved == 'People do stuff.'
-        assert team.getting_paid == 'We pay people.'
+        assert team.onboarding_url == 'http://inside.gratipay.com/'
+        assert team.todo_url == 'https://github.com/gratipay'
 
     def test_401_for_anon_creating_new_team(self):
         self.post_new(self.valid_data, auth_as=None, expected=401)
@@ -73,13 +73,29 @@ def test_error_message_for_no_payout_route(self):
         assert self.db.one("SELECT COUNT(*) FROM teams") == 0
         assert "You must attach a PayPal account to apply for a new team." in r.body
 
+    def test_error_message_for_public_review(self):
+        self.make_participant('alice', claimed_time='now', email_address='alice@example.com', last_paypal_result='')
+        data = dict(self.valid_data)
+        del data['agree_public']
+        r = self.post_new(data, expected=400)
+        assert self.db.one("SELECT COUNT(*) FROM teams") == 0
+        assert "Sorry, you must agree to have your application publicly reviewed." in r.body
+
+    def test_error_message_for_payroll(self):
+        self.make_participant('alice', claimed_time='now', email_address='alice@example.com', last_paypal_result='')
+        data = dict(self.valid_data)
+        del data['agree_payroll']
+        r = self.post_new(data, expected=400)
+        assert self.db.one("SELECT COUNT(*) FROM teams") == 0
+        assert "Sorry, you must agree to be responsible for payroll." in r.body
+
     def test_error_message_for_terms(self):
         self.make_participant('alice', claimed_time='now', email_address='alice@example.com', last_paypal_result='')
         data = dict(self.valid_data)
         del data['agree_terms']
         r = self.post_new(data, expected=400)
         assert self.db.one("SELECT COUNT(*) FROM teams") == 0
-        assert "Please agree to the terms of service." in r.body
+        assert "Sorry, you must agree to the terms of service." in r.body
 
     def test_error_message_for_missing_fields(self):
         self.make_participant('alice', claimed_time='now', email_address='alice@example.com', last_paypal_result='')
@@ -89,6 +105,19 @@ def test_error_message_for_missing_fields(self):
         assert self.db.one("SELECT COUNT(*) FROM teams") == 0
         assert "Please fill out the 'Team Name' field." in r.body
 
+    def test_error_message_for_bad_url(self):
+        self.make_participant('alice', claimed_time='now', email_address='alice@example.com', last_paypal_result='')
+
+        r = self.post_new(dict(self.valid_data, homepage='foo'), expected=400)
+        assert self.db.one("SELECT COUNT(*) FROM teams") == 0
+        assert "Please enter an http[s]:// URL for the 'Homepage' field." in r.body
+
+        r = self.post_new(dict(self.valid_data, onboarding_url='foo'), expected=400)
+        assert "an http[s]:// URL for the 'Self-onboarding Documentation URL' field." in r.body
+
+        r = self.post_new(dict(self.valid_data, todo_url='foo'), expected=400)
+        assert "Please enter an http[s]:// URL for the 'To-do URL' field." in r.body
+
     def test_error_message_for_slug_collision(self):
         self.make_participant('alice', claimed_time='now', email_address='alice@example.com', last_paypal_result='')
         self.post_new(dict(self.valid_data))