func addPlan(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	ctx := r.Context()
	cpuShare, _ := strconv.Atoi(InputValue(r, "cpushare"))
	cpuMilli, _ := strconv.Atoi(InputValue(r, "cpumilli"))
	isDefault, _ := strconv.ParseBool(InputValue(r, "default"))
	memory := getSize(InputValue(r, "memory"))
	swap := getSize(InputValue(r, "swap"))
	plan := appTypes.Plan{
		Name:     InputValue(r, "name"),
		Memory:   memory,
		Swap:     swap,
		CpuShare: cpuShare,
		CPUMilli: cpuMilli,
		Default:  isDefault,
	}
	allowed := permission.Check(t, permission.PermPlanCreate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypePlan, Value: plan.Name},
		Kind:       permission.PermPlanCreate,
		Owner:      t,
		CustomData: event.FormToCustomData(InputFields(r)),
		Allowed:    event.Allowed(permission.PermPlanReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = servicemanager.Plan.Create(ctx, plan)
	if err == appTypes.ErrPlanAlreadyExists {
		return &errors.HTTP{
			Code:    http.StatusConflict,
			Message: err.Error(),
		}
	}
	if err == appTypes.ErrLimitOfMemory || err == appTypes.ErrLimitOfCpuShare {
		return &errors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	if err == nil {
		w.WriteHeader(http.StatusCreated)
		return json.NewEncoder(w).Encode(plan)
	}
	return err
}
title: plan create
path: /plans
method: POST
consume: application/x-www-form-urlencoded
responses:
201: Plan created
400: Invalid data
401: Unauthorized
409: Plan already exists
package api
import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"
	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/permission"
	"github.com/tsuru/tsuru/servicemanager"
	appTypes "github.com/tsuru/tsuru/types/app"
	"k8s.io/apimachinery/pkg/api/resource"
)