code: func (b *Build) PutRequest() (*v1.ApiPutRequestMessage, error) {
  	tags := b.Tags.Copy()
  	tags.Del(v1.TagBuilder) // buildbucket adds it automatically
  	for _, bs := range b.Tags[v1.TagBuildSet] {
  		if !tags.Contains(v1.TagBuildSet, bs) {
  			tags.Add(v1.TagBuildSet, bs)
  		}
  	}
  
  	msg := &v1.ApiPutRequestMessage{
  		Bucket: b.Bucket,
  		Tags:   tags.Format(),
  	}
  
  	parameters := map[string]interface{}{
  		"builder_name": b.Builder,
  		"properties":   b.Input.Properties,
  		// keep this synced with marshaling error annotation
  	}
  	if data, err := json.Marshal(parameters); err != nil {
  		// realistically, only properties may cause this.
  		return nil, errors.Annotate(err, "marshaling properties").Err()
  	} else {
  		msg.ParametersJson = string(data)
  	}
  
  	return msg, nil
  }
docs: // PutRequest converts b to a build creation request.
  //
  // If a buildset is present in both b.BuildSets and b.Map, it is deduped.
  // Returned value has zero ClientOperationId.
  // Returns an error if properties could not be marshaled to JSON.