Import an export document into this organization
https://forumulate.com/api /orgs/{orgId}/import Takes the document GET /orgs/{orgId}/export produces and lands it here. Idempotent, matched by SLUG at every level — re-importing the same document SKIPS what already exists rather than making a second copy of it — and additive: nothing in this organization is deleted because the document does not mention it. Forum spaces carry categories (tree, slugs), pins, accepted answers, polls, reactions (one row per reactor), whispers and each post’s author and createdAt; a post body is block content or markdown. Authors resolve to a member of this org by id, then by members[].email; an address with no account becomes a staged placeholder, and an account outside this org is credited by name only. The reply counts what was created and skipped per level, how each author was attributed, and lists every row that was skipped or changed in warnings. Synchronous: for a large forum, queue it with POST /orgs/{orgId}/imports instead and poll the job. For declaring the shape of a site rather than restoring content, see PUT /orgs/{orgId}/manifest, which dry-runs by default.
Requires token scope: write (the coarse method gate) for Atlas key (ak_), Personal Access Token (cft_) or OAuth (cfo_) auth — in addition to any catalog scope (GET /pats/scopes) the route’s capability needs. Session/cookie auth is governed by RBAC capabilities instead.
Parameters
orgIdstringpathrequiredforumulate-versionstringheaderforumulate-version: 2026-12-01 on every request from a new integration; it is optional only so that integrations written before versioning keep working. Each version includes everything before it:Idempotency-Keystringheader409. The key is scoped to the method and path, so the same key on a different endpoint is a different request. Error responses of 5xx are never cached — those retries re-run. A key is bound to the BODY it was first used with: reusing it with a different body is a 409 idempotency.key_reused, not a replay, because replaying would tell you a write landed that never ran. Generate one key per request, never per process or per session.Request body application/json
formatstringversionintegerexportedAtstringorganizationmembersobject[]Show child parameters
userIdstringrequiredemailstringnamestringavatarUrlstringspacesobject[]Show child parameters
idstringnamestringrequiredslugstringrequiredtypestringrequiredvisibilitystringsettingsobjectcollectionsobject[]Show child parameters
idstringnamestringrequiredslugstringrequiredpagesobject[]Show child parameters
idstringcollectionIdstringrequiredtitlestringrequiredslugstringrequiredcontentmarkdownstringcategoriesobject[]Show child parameters
idstringslugstringrequirednamestringrequireddescriptionstringcolorstringparentstringsortOrderintegerlogoUrlstringtopicsobject[]Show child parameters
idstringtitlestringrequiredslugstringrequiredkindstringstatestringtagsstring[]categoryIdstringcategorystringpinnedbooleanpinnedGloballybooleanfeaturedbooleanlistedbooleanviewCountintegeranswerPostIdstringpollpollsobject[]roadmapStatusstringfieldsobjectunattributedVotesintegercreatedAtstringlastActivityAtstringpostsobject[]{
"format": "string",
"version": 0,
"exportedAt": "string",
"organization": {},
"members": [
{
"userId": "string",
"email": "string",
"name": "string",
"avatarUrl": "string"
}
],
"spaces": [
{
"id": "string",
"name": "string",
"slug": "string",
"type": "string",
"visibility": "string",
"settings": {},
"collections": [
{
"id": null,
"name": null,
"slug": null
}
],
"pages": [
{
"id": null,
"collectionId": null,
"title": null,
"slug": null,
"content": null,
"markdown": null
}
],
"categories": [
{
"id": null,
"slug": null,
"name": null,
"description": null,
"color": null,
"parent": null,
"sortOrder": null,
"logoUrl": null
}
],
"topics": [
{
"id": null,
"title": null,
"slug": null,
"kind": null,
"state": null,
"tags": null,
"categoryId": null,
"category": null,
"pinned": null,
"pinnedGlobally": null,
"featured": null,
"listed": null,
"viewCount": null,
"answerPostId": null,
"poll": null,
"polls": null,
"roadmapStatus": null,
"fields": null,
"unattributedVotes": null,
"createdAt": null,
"lastActivityAt": null,
"posts": null
}
]
}
]
}cURL
curl -X POST "https://forumulate.com/api/orgs/{orgId}/import" \
-H "forumulate-version: <value>" \
-H "Idempotency-Key: <value>" \
-H "Content-Type: application/json" \
-d '{"format":"string","version":0,"exportedAt":"string","organization":{},"members":[{"userId":"string","email":"string","name":"string","avatarUrl":"string"}],"spaces":[{"id":"string","name":"string","slug":"string","type":"string","visibility":"string","settings":{},"collections":[{"id":null,"name":null,"slug":null}],"pages":[{"id":null,"collectionId":null,"title":null,"slug":null,"content":null,"markdown":null}],"categories":[{"id":null,"slug":null,"name":null,"description":null,"color":null,"parent":null,"sortOrder":null,"logoUrl":null}],"topics":[{"id":null,"title":null,"slug":null,"kind":null,"state":null,"tags":null,"categoryId":null,"category":null,"pinned":null,"pinnedGlobally":null,"featured":null,"listed":null,"viewCount":null,"answerPostId":null,"poll":null,"polls":null,"roadmapStatus":null,"fields":null,"unattributedVotes":null,"createdAt":null,"lastActivityAt":null,"posts":null}]}]}'TypeScript
const res = await fetch('https://forumulate.com/api/orgs/{orgId}/import', {
method: 'POST',
headers: {
'forumulate-version': '<value>',
'Idempotency-Key': '<value>',
'Content-Type': 'application/json',
},
body: JSON.stringify({"format":"string","version":0,"exportedAt":"string","organization":{},"members":[{"userId":"string","email":"string","name":"string","avatarUrl":"string"}],"spaces":[{"id":"string","name":"string","slug":"string","type":"string","visibility":"string","settings":{},"collections":[{"id":null,"name":null,"slug":null}],"pages":[{"id":null,"collectionId":null,"title":null,"slug":null,"content":null,"markdown":null}],"categories":[{"id":null,"slug":null,"name":null,"description":null,"color":null,"parent":null,"sortOrder":null,"logoUrl":null}],"topics":[{"id":null,"title":null,"slug":null,"kind":null,"state":null,"tags":null,"categoryId":null,"category":null,"pinned":null,"pinnedGlobally":null,"featured":null,"listed":null,"viewCount":null,"answerPostId":null,"poll":null,"polls":null,"roadmapStatus":null,"fields":null,"unattributedVotes":null,"createdAt":null,"lastActivityAt":null,"posts":null}]}]}),
});
const data = await res.json();Python
import requests
res = requests.request(
"POST",
"https://forumulate.com/api/orgs/{orgId}/import",
headers={
"forumulate-version": "<value>",
"Idempotency-Key": "<value>",
"Content-Type": "application/json",
},
json={"format": "string", "version": 0, "exportedAt": "string", "organization": {}, "members": [{"userId": "string", "email": "string", "name": "string", "avatarUrl": "string"}], "spaces": [{"id": "string", "name": "string", "slug": "string", "type": "string", "visibility": "string", "settings": {}, "collections": [{"id": None, "name": None, "slug": None}], "pages": [{"id": None, "collectionId": None, "title": None, "slug": None, "content": None, "markdown": None}], "categories": [{"id": None, "slug": None, "name": None, "description": None, "color": None, "parent": None, "sortOrder": None, "logoUrl": None}], "topics": [{"id": None, "title": None, "slug": None, "kind": None, "state": None, "tags": None, "categoryId": None, "category": None, "pinned": None, "pinnedGlobally": None, "featured": None, "listed": None, "viewCount": None, "answerPostId": None, "poll": None, "polls": None, "roadmapStatus": None, "fields": None, "unattributedVotes": None, "createdAt": None, "lastActivityAt": None, "posts": None}]}]},
)
data = res.json()Go
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
req, _ := http.NewRequest("POST", "https://forumulate.com/api/orgs/{orgId}/import", strings.NewReader(`{"format":"string","version":0,"exportedAt":"string","organization":{},"members":[{"userId":"string","email":"string","name":"string","avatarUrl":"string"}],"spaces":[{"id":"string","name":"string","slug":"string","type":"string","visibility":"string","settings":{},"collections":[{"id":null,"name":null,"slug":null}],"pages":[{"id":null,"collectionId":null,"title":null,"slug":null,"content":null,"markdown":null}],"categories":[{"id":null,"slug":null,"name":null,"description":null,"color":null,"parent":null,"sortOrder":null,"logoUrl":null}],"topics":[{"id":null,"title":null,"slug":null,"kind":null,"state":null,"tags":null,"categoryId":null,"category":null,"pinned":null,"pinnedGlobally":null,"featured":null,"listed":null,"viewCount":null,"answerPostId":null,"poll":null,"polls":null,"roadmapStatus":null,"fields":null,"unattributedVotes":null,"createdAt":null,"lastActivityAt":null,"posts":null}]}]}`))
req.Header.Set("forumulate-version", "<value>")
req.Header.Set("Idempotency-Key", "<value>")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}PHP
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://forumulate.com/api/orgs/{orgId}/import');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['forumulate-version: <value>', 'Idempotency-Key: <value>', 'Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"format":"string","version":0,"exportedAt":"string","organization":{},"members":[{"userId":"string","email":"string","name":"string","avatarUrl":"string"}],"spaces":[{"id":"string","name":"string","slug":"string","type":"string","visibility":"string","settings":{},"collections":[{"id":null,"name":null,"slug":null}],"pages":[{"id":null,"collectionId":null,"title":null,"slug":null,"content":null,"markdown":null}],"categories":[{"id":null,"slug":null,"name":null,"description":null,"color":null,"parent":null,"sortOrder":null,"logoUrl":null}],"topics":[{"id":null,"title":null,"slug":null,"kind":null,"state":null,"tags":null,"categoryId":null,"category":null,"pinned":null,"pinnedGlobally":null,"featured":null,"listed":null,"viewCount":null,"answerPostId":null,"poll":null,"polls":null,"roadmapStatus":null,"fields":null,"unattributedVotes":null,"createdAt":null,"lastActivityAt":null,"posts":null}]}]}');
$response = curl_exec($ch);
curl_close($ch);
echo $response;Ruby
require 'net/http'
require 'uri'
uri = URI('https://forumulate.com/api/orgs/{orgId}/import')
req = Net::HTTP::Post.new(uri)
req['forumulate-version'] = '<value>'
req['Idempotency-Key'] = '<value>'
req['Content-Type'] = 'application/json'
req.body = '{"format":"string","version":0,"exportedAt":"string","organization":{},"members":[{"userId":"string","email":"string","name":"string","avatarUrl":"string"}],"spaces":[{"id":"string","name":"string","slug":"string","type":"string","visibility":"string","settings":{},"collections":[{"id":null,"name":null,"slug":null}],"pages":[{"id":null,"collectionId":null,"title":null,"slug":null,"content":null,"markdown":null}],"categories":[{"id":null,"slug":null,"name":null,"description":null,"color":null,"parent":null,"sortOrder":null,"logoUrl":null}],"topics":[{"id":null,"title":null,"slug":null,"kind":null,"state":null,"tags":null,"categoryId":null,"category":null,"pinned":null,"pinnedGlobally":null,"featured":null,"listed":null,"viewCount":null,"answerPostId":null,"poll":null,"polls":null,"roadmapStatus":null,"fields":null,"unattributedVotes":null,"createdAt":null,"lastActivityAt":null,"posts":null}]}]}'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts res.bodyJava
import java.net.URI;
import java.net.http.*;
import java.net.http.HttpRequest.BodyPublishers;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://forumulate.com/api/orgs/{orgId}/import"))
.header("forumulate-version", "<value>")
.header("Idempotency-Key", "<value>")
.header("Content-Type", "application/json")
.method("POST", BodyPublishers.ofString("{\"format\":\"string\",\"version\":0,\"exportedAt\":\"string\",\"organization\":{},\"members\":[{\"userId\":\"string\",\"email\":\"string\",\"name\":\"string\",\"avatarUrl\":\"string\"}],\"spaces\":[{\"id\":\"string\",\"name\":\"string\",\"slug\":\"string\",\"type\":\"string\",\"visibility\":\"string\",\"settings\":{},\"collections\":[{\"id\":null,\"name\":null,\"slug\":null}],\"pages\":[{\"id\":null,\"collectionId\":null,\"title\":null,\"slug\":null,\"content\":null,\"markdown\":null}],\"categories\":[{\"id\":null,\"slug\":null,\"name\":null,\"description\":null,\"color\":null,\"parent\":null,\"sortOrder\":null,\"logoUrl\":null}],\"topics\":[{\"id\":null,\"title\":null,\"slug\":null,\"kind\":null,\"state\":null,\"tags\":null,\"categoryId\":null,\"category\":null,\"pinned\":null,\"pinnedGlobally\":null,\"featured\":null,\"listed\":null,\"viewCount\":null,\"answerPostId\":null,\"poll\":null,\"polls\":null,\"roadmapStatus\":null,\"fields\":null,\"unattributedVotes\":null,\"createdAt\":null,\"lastActivityAt\":null,\"posts\":null}]}]}"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());Responses
Example
{
"summary": {
"authors": {
"email": 0,
"member": 0,
"name": 0,
"staged": 0
},
"categoriesCreated": 0,
"collectionsCreated": 0,
"pagesCreated": 0,
"pagesSkipped": 0,
"pollVotesCreated": 0,
"postsCreated": 0,
"spacesCreated": 0,
"spacesReused": 0,
"topicsCreated": 0,
"topicsFailed": 0,
"topicsSkipped": 0,
"warnings": [
{
"message": "string",
"path": "string"
}
],
"warningsTruncated": true
},
"warnings": [
"tags: \"Launch Day\" is stored as \"launch-day\""
]
}Schema
summaryobjectrequiredShow child parameters
authorsobjectrequiredShow child parameters
emailnumberrequiredmembernumberrequirednamenumberrequiredstagednumberrequiredcategoriesCreatednumberrequiredcollectionsCreatednumberrequiredpagesCreatednumberrequiredpagesSkippednumberrequiredpollVotesCreatednumberrequiredpostsCreatednumberrequiredspacesCreatednumberrequiredspacesReusednumberrequiredtopicsCreatednumberrequiredtopicsFailednumberrequiredtopicsSkippednumberrequiredwarningsImportWarning[]requiredShow child parameters
messagestringrequiredpathstringrequiredwarningsTruncatedbooleanwarningsstring[][]. The same sentences are on the X-Field-Warnings response header. If this is present, something you sent is not what is stored; read the resource back rather than assuming your own value.request.malformed). A value that was understood but is not acceptable is a 422 validation.failed.Example
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}Schema
errorobjectrequiredShow child parameters
codestringrequiredrbac.forbidden.messagestringrequireddetailsobjectdocsstringGET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.reasonstringiat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.slugsstring[]space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.conflictobjectPATCH …/entries/{entryId}/fields) whose If-Match was stale.Show child parameters
etagstringrequiredopsarrayrequiredIf-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.requestIdstringx-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.auth.required). Send a Bearer token or the session cookie.Example
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}Schema
errorobjectrequiredShow child parameters
codestringrequiredrbac.forbidden.messagestringrequireddetailsobjectdocsstringGET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.reasonstringiat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.slugsstring[]space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.conflictobjectPATCH …/entries/{entryId}/fields) whose If-Match was stale.Show child parameters
etagstringrequiredopsarrayrequiredIf-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.requestIdstringx-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.rbac.forbidden, whether what is missing is the capability, the token scope, or a resource the token is pinned away from. The message names the capability and, for a scope refusal, the scopes that would grant it. A refusal because of the PLAN is a 402 with quota.exceeded, not this.Example
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}Schema
errorobjectrequiredShow child parameters
codestringrequiredrbac.forbidden.messagestringrequireddetailsobjectdocsstringGET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.reasonstringiat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.slugsstring[]space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.conflictobjectPATCH …/entries/{entryId}/fields) whose If-Match was stale.Show child parameters
etagstringrequiredopsarrayrequiredIf-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.requestIdstringx-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.*.not_found).Example
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}Schema
errorobjectrequiredShow child parameters
codestringrequiredrbac.forbidden.messagestringrequireddetailsobjectdocsstringGET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.reasonstringiat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.slugsstring[]space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.conflictobjectPATCH …/entries/{entryId}/fields) whose If-Match was stale.Show child parameters
etagstringrequiredopsarrayrequiredIf-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.requestIdstringx-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.validation.failed). error.details names the field paths.Example
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}Schema
errorobjectrequiredShow child parameters
codestringrequiredrbac.forbidden.messagestringrequireddetailsobjectdocsstringGET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.reasonstringiat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.slugsstring[]space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.conflictobjectPATCH …/entries/{entryId}/fields) whose If-Match was stale.Show child parameters
etagstringrequiredopsarrayrequiredIf-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.requestIdstringx-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.Example
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}Schema
errorobjectrequiredShow child parameters
codestringrequiredrbac.forbidden.messagestringrequireddetailsobjectdocsstringGET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.reasonstringiat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.slugsstring[]space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.conflictobjectPATCH …/entries/{entryId}/fields) whose If-Match was stale.Show child parameters
etagstringrequiredopsarrayrequiredIf-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.requestIdstringx-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.Example
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}Schema
errorobjectrequiredShow child parameters
codestringrequiredrbac.forbidden.messagestringrequireddetailsobjectdocsstringGET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.reasonstringiat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.slugsstring[]space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.conflictobjectPATCH …/entries/{entryId}/fields) whose If-Match was stale.Show child parameters
etagstringrequiredopsarrayrequiredIf-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.requestIdstringx-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.