diff --git a/plugins/apiv3_example.rb b/plugins/apiv3_example.rb
index d6c71474d0..f7456d8038 100644
--- a/plugins/apiv3_example.rb
+++ b/plugins/apiv3_example.rb
@@ -1,15 +1,43 @@
module Jekyll
class ApiV3Example < Liquid::Block
def initialize(tag_name, markup, tokens)
+
attributes = markup.split
+
@identifier = attributes[0]
@request_type = attributes[1]
@url = attributes[2]
- @data = markup.gsub(attributes[0],"").gsub(attributes[1],"").gsub(attributes[2],"").strip
+ #clean the original attributes from the original content
+ markup = markup.gsub(@identifier,"").gsub(@request_type,"").gsub(@url,"")
+
+ #get the data - which is "request data" and "request headers" if they exist
+ @data, @request_header = markup.scan(/\{(.*?)\}/)
+
+ unless @data.nil?
+ #hack it back together now
+ @data = "{"+@data[0].to_s+"}"
+ markup = markup.gsub("{"+@data[0].to_s+"}", "")
+ if @data = "{}"
+ @data = ""
+ end
+ end
+
+ unless @request_header.nil?
+ @request_header = @request_header[0]
+ markup = markup.gsub("{"+@request_header.to_s+"}", "")
+
+ if @request_header.include? "request_header"
+ @request_header = @request_header.gsub("request_header","")
+ else
+ #this isn't a request header and it's out of order
+ @data = "{"+@request_header.to_s+"}"
+ @request_header = ""
+ end
+ end
- if attributes[4]
- @show_livedoc = attributes[4]
+ if markup.strip.length > 0
+ @show_livedoc = markup
end
super
@@ -18,7 +46,6 @@ def initialize(tag_name, markup, tokens)
def render(context)
output = super
-
output = <
#{output}
@@ -32,7 +59,8 @@ def render_all(list, context)
context['identifier'] = @identifier
context['request_type'] = @request_type
context['url'] = @url
- context['data'] = @data
+ context['data'] = @data.to_s
+ context['request_header'] = @request_header.to_s
super
end
end
@@ -53,13 +81,16 @@ def unquote_data(data)
def render(context)
output = super
-
+
# let's parse the vars before we generate the output to avoid complications
identifier = Liquid::Template.parse("{{ identifier }}").render context
request_type = Liquid::Template.parse("{{ request_type }}").render context
url = Liquid::Template.parse("{{ url }}").render context
+ request_header = Liquid::Template.parse("{{ request_header }}").render context
data = Liquid::Template.parse("{{ data }}").render context
+ data_block = '';
+
if data.include? "="
data = Hash[URI.decode_www_form(data)]
data = unquote_data(data)
@@ -68,9 +99,15 @@ def render(context)
data = data.length > 0 ? JSON.pretty_generate(JSON.parse(data)) : ""
end
+ if request_header.length > 0
+ request_header = request_header.gsub('-_-',"")
+ data_block = "Request Headers
{% codeblock %}#{request_header}{% endcodeblock %}"
+ end
+
if data.length > 0
- data_block = "Request Body
{% codeblock lang:json %}#{data}{% endcodeblock %}"
- end
+ data_block += "Request Body
{% codeblock lang:json %}#{data}{% endcodeblock %}"
+ end
+
request_url = url
output = <
HTML
-
+
return Liquid::Template.parse(output).render context
end
end
diff --git a/plugins/converter_apiblueprint.rb b/plugins/converter_apiblueprint.rb
index 3da8633169..52aede6965 100644
--- a/plugins/converter_apiblueprint.rb
+++ b/plugins/converter_apiblueprint.rb
@@ -42,6 +42,7 @@ class BluePrintHTML < Redcarpet::Render::HTML
@@path = ""
@@request_body = ""
@@response_body = ""
+ @@request_headers = ""
####
# set the root url of the API calls
@@ -137,8 +138,14 @@ def header(text, level, somethingelse = nil)
# get the request method
if 3 == level
debug "\t--RESET VARS--"
- # get the response method from the header
- @@method = text.split("[")[1].gsub("]","")
+ if text.include? "]"
+ # get the response method from the header
+ @@method = text.split("[")[1].gsub("]","")
+ else
+ debug "HEADER parse error - no HTTP method on " + text
+ exit
+ end
+
debug "\tMETHOD SET: " + @@method
end
@@ -198,10 +205,14 @@ def list_item(text, list_type)
end
#handle the request and response headers
- if text.include? "Header"
- # @todo build this out!
- end
+ # When we have headers that tag along, we need to indicate this
+ if text.include? "Headers"
+ debug "HEADERS!! " + text
+
+ return docs_header(text)
+
+ end
# next up is an element with Body - we don't know whether it's a request or a response
if text.include? "Body"
@@ -293,14 +304,35 @@ def do_find_replace(text, index)
return text.to_s
end
+ def docs_header(text)
+
+ text = text.gsub("Headers","")
+
+ debug "In docs_header body_block = " + @@body_block
+
+ if "request" == @@body_block
+ debug "Found a header! " + text
+
+ @@request_headers = text.gsub("\n","").gsub(""",'"')
+
+ end
+
+ if "response" == @@body_block
+ #@todo build this out
+ end
+
+ end
+
# handle the body of the request or response
def docs_body(text)
debug "\t --docs_body--"
text = text.gsub("Body","")
+ debug "Body Block: " + @@body_block
+
if "request" == @@body_block
- @@request_body = text.gsub("\n","")
+ @@request_body = text.gsub("\n","").gsub(""",'"')
debug "\t REQUEST BODY SET " + text.strip
@@ -434,6 +466,27 @@ def docs_liquid_output(text)
url += " " + @@request_body.strip
end
+ debug "REQUEST HEADERS: " + @@request_headers
+
+ if @@request_headers.length > 1
+
+ debug "WE HAVE REQUEST HEADERS"
+
+ #make sure that we have the space there to be parsed
+
+ if @@request_body.length <= 1
+ debug "REquest Body is 0"
+ url += " {}"
+ end
+
+ debug "adding request headers to URL"
+
+ #add the request headers to the tag
+ url += " {request_header" + @@request_headers.strip + "}"
+
+ debug "####URL####" + url
+ end
+
# output all the tags at once for this endpoint
# if/when we want to put params on the URL in the Request area, we can do this append - @@params.gsub("\n","")+ - to the Url
# we will need to probably grab params for the URL from the params list, rather than the request body
@@ -493,7 +546,7 @@ def docs_liquid_params_block(text)
def reset_vars()
debug "## RESET EVERYTHING ##"
# reset everything, just in case we're about to do another endpoint - path doesn't get reset until another h2, bc we reuse the path
- @@body_block, @@group_identifier, @@http_response, @@params, @@request_body, @@response_body = "","","","","","",""
+ @@body_block, @@group_identifier, @@http_response, @@params, @@request_body, @@response_body, @@request_headers = "","","","","","","",""
end
end
\ No newline at end of file
diff --git a/source/API_Reference/Customer_Subuser_API/subusers.md b/source/API_Reference/Customer_Subuser_API/subusers.md
index 1fd82ab0ad..d532052bb9 100644
--- a/source/API_Reference/Customer_Subuser_API/subusers.md
+++ b/source/API_Reference/Customer_Subuser_API/subusers.md
@@ -22,7 +22,7 @@ Create a Subuser
{% parameters create %}
{% parameter username Yes 'No more than 64 characters' 'New subuser username' %}
- {% parameter password Yes 'At least 6 characters' 'New subuser password' %}
+ {% parameter password Yes 'At least 8 characters' 'New subuser password' %}
{% parameter confirm_password Yes 'Match password argument' 'Confirm new password' %}
{% parameter email Yes 'Valid email address, no more than 64 characters' 'New subuser email. This is an administrative contact address for SendGrid' %}
{% parameter first_name Yes 'No more than 50 characters' 'New subuser profile first name' %}
diff --git a/source/API_Reference/Web_API_v3/API_Keys/index.apiblueprint b/source/API_Reference/Web_API_v3/API_Keys/index.apiblueprint
new file mode 100644
index 0000000000..d472f3b52d
--- /dev/null
+++ b/source/API_Reference/Web_API_v3/API_Keys/index.apiblueprint
@@ -0,0 +1,198 @@
+---
+layout: page
+weight: 755
+title: API Keys
+navigation:
+ show: true
+---
+
+FORMAT: 1A
+
+# API Keys
+The API Keys feature allows customers to be able to generate an
+API Key credential which can be used for authentication with the
+SendGrid v3 Web API or Mail API.
+
+# Group API Keys management
+
+## API Keys collection [/api_keys]
+### List all API Keys belonging to the authenticated user [GET]
+
++ Response 200 (application/json)
+
+ + Body
+
+ {
+ "result": [
+ {
+ "name": "A New Hope",
+ "api_key_id": "xxxxxxxx"
+ }
+ ]
+ }
+
+### Generate a new API Key for the authenticated user [POST]
+This will create a new random API Key for the user.
+A JSON request body containing a "name" property is required.
+If number of maximum keys is reached, HTTP 403 will be returned.
+
++ Request
+
+ + Body
+
+ {
+ "name":"My API Key"
+ }
+
++ Response 201 (application/json)
+
+ {
+ "api_key": "SG.xxxxxxxx.yyyyyyyy",
+ "api_key_id": "xxxxxxxx"
+ "name": "My API Key"
+ }
+
++ Response 400 (application/json)
+
+ + Body
+
+ {
+ "errors": [
+ {
+ "field": "name",
+ "message": "missing required argument"
+ }
+ ]
+ }
+
++ Response 403 (application/json)
+
+ + Body
+
+ {
+ "errors": [
+ {
+ "field": null,
+ "message": "Cannot create more than 100 API Keys"
+ }
+ ]
+ }
+
+## API Key [/api_keys/{api_key}]
+### Revoke an existing API Key [DELETE]
+Authentications using this API Key will fail
+after this request is made, with some small propogation delay.
+
+If the API Key ID does not exist an HTTP 404 will be returned.
+
++ Response 204 (application/json)
+
++ Response 404 (application/json)
+
+ + Body
+
+ {
+ "errors": [
+ {
+ "field": null,
+ "message": "unable to find API Key for deletion"
+ }
+ ]
+ }
+
+### Update the name of an existing API Key [PATCH]
+A JSON request body with a "name" property is required.
+
++ Request
+
+ + Body
+
+ {
+ "name": "A New Hope"
+ }
+
++ Response 200 (application/json)
+
+ + Body
+
+ {
+ "api_key_id": "qfTQ6KG0QBiwWdJ0-pCLCA",
+ "name": "A New Hope"
+ }
+
++ Response 400 (application/json)
+
+ + Body
+
+ {
+ "errors": [
+ {
+ "field": null,
+ "message": "expected JSON request body with 'name' property"
+ }
+ ]
+ }
+
++ Response 404 (application/json)
+
+ + Body
+
+ {
+ "errors": [
+ {
+ "field": null,
+ "message": "unable to find API Key to update"
+ }
+ ]
+ }
+
+# Group API Key usage
+The API Keys feature adds a new "Bearer" scheme for HTTP authentication
+for both v3 WebAPI and the mail.send API.
+
+## Authentication against a /v3 API resource [/resource]
+Returns HTTP 401 if authentication fails.
+
+### Authentication [GET]
++ Request
+
+ + Headers
+
+ Authorization: Bearer SG.xxxxxxxx.yyyyyyyy
+
++ Response 200 (application/json)
+
++ Response 401 (application/json)
+
+ {
+ "errors": [
+ {
+ "field": null,
+ "message": "authorization required"
+ }
+ ]
+ }
+
+
+## Authentication against the mail.send API [/api/mail.send.json]
+Returns HTTP 400 if authentication fails.
+
+### HTTP Authentication [GET]
++ Request
+
+ + Headers
+
+ Authorization: Bearer SG.xxxxxxxx.yyyyyyyy
+
++ Response 200 (application/json)
+
++ Response 400 (application/json)
+
+ + Body
+
+ {
+ "message": "error",
+ "errors": [
+ "invalid API Key"
+ ]
+ }
\ No newline at end of file
diff --git a/source/User_Guide/Account/api_keys.md b/source/User_Guide/Account/api_keys.md
index 8aa3730d18..cae1f18971 100644
--- a/source/User_Guide/Account/api_keys.md
+++ b/source/User_Guide/Account/api_keys.md
@@ -26,7 +26,7 @@ Permissions that allow you to define what a given API Key is allowed to do are i
Managing API Keys
{%endanchor%}
-You can [manage your API Keys](https://sendgrid.com/beta/settings/api_keys) from our beta interface.
+You can [manage your API Keys](https://sendgrid.com/beta/settings/api_keys) from our beta interface. Additionally, you can [manage your API keys via the API itself]({{root_url}}/API_Reference/Web_API_v3/API_Keys/index.html)).
{% anchor h2%}
Using API Keys