Importing creators
importCreators adds creators to your workspace from their social
handles. It runs the same import engine as Creators → Import from file in the Archive app: each
creator is matched to an existing creator or created from their handles, and the labels you send
are applied to them, with any label the workspace does not have yet created on the way.
The mutation only accepts the batch. The import itself runs in the background, and you follow it through the operation it returns.
Send a batch
Each request carries 1 to 250 creators. A creator is a list of 1 to 5 handles, each a
{ provider, handle } pair, plus optional labels:
providerisINSTAGRAM,TIKTOKorYOUTUBE.handleis the creator’s handle on that platform, with or without a leading@, or their profile URL there.labelsholds up to 20 distinct label names per creator, each up to 100 characters (counted in Unicode code points). Names are trimmed, and blank or exactly repeated names are ignored. Names that differ only in case each count toward the 20-name cap.
A request that breaks any of these caps is refused as a whole: nothing is imported, and a
userErrors entry says why. When the cap belongs to one creator, its field points at that
creator, for example ["creators", "3", "labels"].
mutation ImportCreatorsDefault($creators: [CreatorImportInput!]!, $operationId: ID) {
importCreators(creators: $creators, operationId: $operationId) {
operationId
acceptedCount
skipped {
index
provider
handle
reason
}
userErrors {
field
message
}
}
} {
"creators": [
{
"handles": [
{
"provider": "INSTAGRAM",
"handle": "@maya.greenhouse"
},
{
"provider": "TIKTOK",
"handle": "mayagreenhouse"
}
],
"labels": [
"Q4 seeding"
]
},
{
"handles": [
{
"provider": "YOUTUBE",
"handle": "fernandfrondstudio"
}
]
},
{
"handles": [
{
"provider": "INSTAGRAM",
"handle": "not a handle!"
}
]
}
],
"operationId": "3f1c9a52-7d4e-4b8a-9c21-6e5f0a7b8d13"
} Authorization: Bearer docs_demo_token_0000000000000000000000
WORKSPACE-ID: 6ccefa76-e8ba-5ab0-9c60-e48a9e235a4a curl https://app.archive.com/api/v2 \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer docs_demo_token_0000000000000000000000' \
-H 'WORKSPACE-ID: 6ccefa76-e8ba-5ab0-9c60-e48a9e235a4a' \
-d '{
"query": "mutation ImportCreatorsDefault($creators: [CreatorImportInput!]!, $operationId: ID) {\n importCreators(creators: $creators, operationId: $operationId) {\n operationId\n acceptedCount\n skipped {\n index\n provider\n handle\n reason\n }\n userErrors {\n field\n message\n }\n }\n}",
"variables": {
"creators": [
{
"handles": [
{
"provider": "INSTAGRAM",
"handle": "@maya.greenhouse"
},
{
"provider": "TIKTOK",
"handle": "mayagreenhouse"
}
],
"labels": [
"Q4 seeding"
]
},
{
"handles": [
{
"provider": "YOUTUBE",
"handle": "fernandfrondstudio"
}
]
},
{
"handles": [
{
"provider": "INSTAGRAM",
"handle": "not a handle!"
}
]
}
],
"operationId": "3f1c9a52-7d4e-4b8a-9c21-6e5f0a7b8d13"
}
}' const response = await fetch("https://app.archive.com/api/v2", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer docs_demo_token_0000000000000000000000",
"WORKSPACE-ID": "6ccefa76-e8ba-5ab0-9c60-e48a9e235a4a"
},
body: JSON.stringify({
query: `mutation ImportCreatorsDefault($creators: [CreatorImportInput!]!, $operationId: ID) {
importCreators(creators: $creators, operationId: $operationId) {
operationId
acceptedCount
skipped {
index
provider
handle
reason
}
userErrors {
field
message
}
}
}`,
variables: {
"creators": [
{
"handles": [
{
"provider": "INSTAGRAM",
"handle": "@maya.greenhouse"
},
{
"provider": "TIKTOK",
"handle": "mayagreenhouse"
}
],
"labels": [
"Q4 seeding"
]
},
{
"handles": [
{
"provider": "YOUTUBE",
"handle": "fernandfrondstudio"
}
]
},
{
"handles": [
{
"provider": "INSTAGRAM",
"handle": "not a handle!"
}
]
}
],
"operationId": "3f1c9a52-7d4e-4b8a-9c21-6e5f0a7b8d13"
}
})
})
console.log(JSON.stringify(await response.json(), null, 2)) require "json"
require "net/http"
query = <<~'GRAPHQL'
mutation ImportCreatorsDefault($creators: [CreatorImportInput!]!, $operationId: ID) {
importCreators(creators: $creators, operationId: $operationId) {
operationId
acceptedCount
skipped {
index
provider
handle
reason
}
userErrors {
field
message
}
}
}
GRAPHQL
response = Net::HTTP.post(
URI("https://app.archive.com/api/v2"),
{ query: query, variables: { "creators" => [{ "handles" => [{ "provider" => "INSTAGRAM", "handle" => "@maya.greenhouse" }, { "provider" => "TIKTOK", "handle" => "mayagreenhouse" }], "labels" => ["Q4 seeding"] }, { "handles" => [{ "provider" => "YOUTUBE", "handle" => "fernandfrondstudio" }] }, { "handles" => [{ "provider" => "INSTAGRAM", "handle" => "not a handle!" }] }], "operationId" => "3f1c9a52-7d4e-4b8a-9c21-6e5f0a7b8d13" } }.to_json,
"Content-Type" => "application/json",
"Authorization" => "Bearer docs_demo_token_0000000000000000000000",
"WORKSPACE-ID" => "6ccefa76-e8ba-5ab0-9c60-e48a9e235a4a"
)
puts response.body import json
import requests
query = """
mutation ImportCreatorsDefault($creators: [CreatorImportInput!]!, $operationId: ID) {
importCreators(creators: $creators, operationId: $operationId) {
operationId
acceptedCount
skipped {
index
provider
handle
reason
}
userErrors {
field
message
}
}
}
"""
response = requests.post(
"https://app.archive.com/api/v2",
json={"query": query, "variables": {"creators": [{"handles": [{"provider": "INSTAGRAM", "handle": "@maya.greenhouse"}, {"provider": "TIKTOK", "handle": "mayagreenhouse"}], "labels": ["Q4 seeding"]}, {"handles": [{"provider": "YOUTUBE", "handle": "fernandfrondstudio"}]}, {"handles": [{"provider": "INSTAGRAM", "handle": "not a handle!"}]}], "operationId": "3f1c9a52-7d4e-4b8a-9c21-6e5f0a7b8d13"}},
headers={
"Authorization": "Bearer docs_demo_token_0000000000000000000000",
"WORKSPACE-ID": "6ccefa76-e8ba-5ab0-9c60-e48a9e235a4a",
},
)
print(json.dumps(response.json(), indent=2)) {
"data": {
"importCreators": {
"operationId": "3f1c9a52-7d4e-4b8a-9c21-6e5f0a7b8d13",
"acceptedCount": 2,
"skipped": [
{
"index": 2,
"provider": "INSTAGRAM",
"handle": "not a handle!",
"reason": "INVALID_HANDLE"
}
],
"userErrors": []
}
}
} Retry with the same operationId
Mint a version 4 UUID for each logical import and send it as operationId. If the request times
out or the connection drops, send it again with the same operationId:
- If the first request got through, the retry is refused with a
userErrorsentry on["operationId"]and the first import keeps running. The HTTP response is still200; there is no HTTP409. Poll the operation with the id you minted. - If it did not, the retry starts the import.
Never resubmit without the id while you wait for an import. A request without an operationId, or
with a new one, starts a second import of the same creators.
A request can also be refused because another import is updating the workspace’s labels at that
moment. It gets a userErrors entry on ["base"] asking you to retry, and nothing is imported.
Retrying it with the same operationId is safe.
Skipped creators
A creator that cannot be imported is reported in skipped instead of failing the whole request.
Each entry is { index, provider, handle, reason }, where index is the creator’s position in
creators:
INVALID_HANDLE— a handle is not a valid handle or profile URL on its platform.NO_HANDLES— the creator had no handles left to import.UNKNOWN_PROVIDER— a handle named a platform the import does not support.
acceptedCount counts the creators that were accepted. Fix a skipped creator’s handle before you
send it again; resending it unchanged skips it again. When every creator is skipped, no import is
started and operationId is null.
Follow the import
When importCreators returns, nothing has been imported yet. Follow the operation in one of two
ways:
- Poll. Query
operation(id:)with theoperationIduntilstatusisCOMPLETED,PARTIALorFAILED. A creator import reportsoperationTypeoneschema_creator_importandimportSourcePUBLIC_API. - Subscribe. Point a webhook subscription at the
operation.completedevent and wait for it. See operation completion events.
Then page through operationRecords(operationId:) for the outcome of
each creator. On a creator-import record, itemId is the row key within the import (import_0,
import_1, and so on), not an item id, and the record carries:
handles— the handles you sent for that creator;creatorId— the creator aSUCCEEDEDrow created or updated, an input tocreator(id:);errorCodeanderrorMessage— why aFAILEDrow failed, the message in words fit to show a person.
The deprecated succeededItemIds, failedItemIds and pendingItemIds lists on Operation are
always empty for a creator import; use operationRecords instead.
Result CSVs
A PARTIAL or FAILED import also gets CSV files of its rows, written shortly after it finishes:
failedRecordsCsvUrl— the rows that failed, each with its error (PARTIALandFAILED).successfulRecordsCsvUrl— the rows that were imported (PARTIALonly).
A COMPLETED import has no CSVs, and both fields are null until the files are written. Each link
is valid for 1 hour; query the operation again for a fresh one.
Pricing
The import itself charges no credits. Magic fields that run on the imported creators bill exactly as they do for creators imported in the app. The request costs the same weighted rate-limit points as any other mutation; see rate limits.
Attribution
The import is recorded as made by a person in your workspace, as imports made in the app are:
- the user who authorized the OAuth token, if they are a member of the workspace;
- otherwise the person who issued the API token, if they are a member;
- otherwise the workspace’s creator, if they are still a member and not an Archive employee;
- otherwise the workspace’s earliest-joined member who is not an Archive employee.
If none of them applies, the request is refused with a userErrors entry on ["base"].
Regenerating an API token in the app makes you its issuer.
From an MCP client
The importCreators MCP tool takes the same creators and
operationId arguments and returns the same payload. Poll the import with getOperation, read its
rows with getOperationRecords, and pass a row’s creatorId to getCreator.